Struct Member Variable not Defined - has no member named - c

I have a struct defined in a file called sock.h:
struct pj_sockaddr_in
{
#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
pj_uint8_t sin_zero_len; /**< Just ignore this. */
pj_uint8_t sin_family; /**< Address family. */
#else
pj_uint16_t sin_family; /**< Address family. */
#endif
pj_uint16_t sin_port; /**< Transport layer port number. */
pj_in_addr sin_addr; /**< IP address. */
char sin_zero[PJ_SOCKADDR_IN_SIN_ZERO_LEN]; /**< Padding.*/
};
It is referenced from sock_common.c file:
PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
const pj_str_t *str_addr,
pj_uint16_t port)
{
PJ_ASSERT_RETURN(addr, (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
PJ_SOCKADDR_RESET_LEN(addr);
addr->sin_family = PJ_AF_INET;
pj_bzero(addr->sin_zero, sizeof(addr->sin_zero));
pj_sockaddr_in_set_port(addr, port);
return pj_sockaddr_in_set_str_addr(addr, str_addr);
}
It runs into a compilation error which I couldn't figure out why:
In function 'pj_sockaddr_in_init':
sock_common.c:error: 'pj_sockaddr_in' has no member named 'sin_zero'
My question is how is it possible for a field to be ignored? Other fields in the struct is visible and could be referenced. Any thoughts?
PS: Project source code if interested: http://svn.pjsip.org/repos/pjproject/trunk

C struct types actually have struct as part of their name. Your function definition should be (based on your struct definition)
PJ_DEF(pj_status_t) pj_sockaddr_in_init( struct pj_sockaddr_in *addr,
const pj_str_t *str_addr,
pj_uint16_t port)
However, it is much more common to just use a typedef in the declaration:
typedef struct
{
#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
pj_uint8_t sin_zero_len; /**< Just ignore this. */
pj_uint8_t sin_family; /**< Address family. */
#else
pj_uint16_t sin_family; /**< Address family. */
#endif
pj_uint16_t sin_port; /**< Transport layer port number. */
pj_in_addr sin_addr; /**< IP address. */
char sin_zero[PJ_SOCKADDR_IN_SIN_ZERO_LEN]; /**< Padding.*/
} pj_sockaddr_in;

After spending some time, I figured out that the following statement:
#undef sin_zero
in http://svn.pjsip.org/repos/pjproject/trunk/pjlib/include/pj/compat/socket.h caused the problem. I am posting this here so that it may help others running into the same issue with PJSIP.

Related

Get IP version from packet data

The pcap callback function returns the IP header and data as follows:
void packet_handler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data);
My understanding is the first 4 bits of the pkt_data is the IP version from which I can determine it is is IPv4 or IPv6. However, I've tried a few different ways to read the first 4 bits and I'm getting data that does not make sense.
For example, I defined the following structure:
struct ipdata {
u_char version : 4;
u_char dontcare : 4;
};
And then I tried to get the ip version using this code:
ipdata* pipdata;
pipdata = (ipdata*) pkt_data;
ip_ver = pipdata->version;
printf(" %d ", ip_ver);
The above method prints values of 3, 6, 9, 8 and 12. If I watch the traffic at the same time in Wireshark I see that most of the packets are IPv6.
Could someone who has done this clarify how would I go about reading the IP version?
Figure out the answer. Npcap returns the entire ethernet packet, so the first 14 bytes are the Ethernet header:
/* Length of the Ethernet Header (Data Link Layer) */
#define ETHERNET_HEADER_LEN 14
/* Ethernet addresses are 6 bytes */
#define ETHER_ADDR_LEN 6
/* Ethernet header */
struct sniff_ethernet {
u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address (i.e. Destination MAC Address) */
u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address (i.e. Source MAC Address) */
u_short ether_type; /* IP? ARP? RARP? etc */
};
You can figure out whether it is an IPv4 or IPv6 packet by looking at the ether_type in the above structure rather than the version in the IP header, such as:
/* Common ethernet types in Hex*/
#define ETHERNET_TYPE_IPv4 0x0800
#define ETHERNET_TYPE_IPv6 0x86DD
u_short eth_type;
ethernet = (struct sniff_ethernet*)(pkt_data);
eth_type = ntohs(ethernet->ether_type);
if (eth_type == ETHERNET_TYPE_IPv4) {
ipv4_handler(pkt_data);
}
else if (eth_type == ETHERNET_TYPE_IPv6)
{
ipv6_handler(pkt_data);
}
The IP header starts right after the ethernet header, so you can get it with code such as the following example for an IPv6 packet:
/* IPv6 header */
typedef struct ipv6_header
{
unsigned int
version : 4,
traffic_class : 8,
flow_label : 20;
uint16_t length;
uint8_t next_header;
uint8_t hop_limit;
struct in6_addr saddr;
struct in6_addr daddr;
} ipv6_header;
const ipv6_header* iph;
iph = (ipv6_header*)(pkt_data + ETHERNET_HEADER_LEN);
From there you can access the version and other information about the IP header. See this post for more information: Getting Npcap IPv6 source and destination addresses

Obtain interface netmask in Linux kernel module

I write Linux kernel module with netfilter hook. I want to block any packet that is not from my subnet.
Is there any simple method to get netmask of the interface in kernel-mode? I found only the way to get it using ioctl() in user-mode.
There is a pretty easy way to get it.
Network device is described by struct net_device.
<linux/netdevice.h>:
struct net_device {
...
struct in_device __rcu *ip_ptr;
...
net_device has a pointer to "inet" device (in_device).
<linux/inetdevice.h>:
struct in_device {
...
struct in_ifaddr *ifa_list; /* IP ifaddr chain */
...
which finnaly points to chain of in_ifaddr that contains all the interface info:
struct in_ifaddr {
struct hlist_node hash;
struct in_ifaddr *ifa_next;
struct in_device *ifa_dev;
struct rcu_head rcu_head;
__be32 ifa_local;
__be32 ifa_address;
__be32 ifa_mask;
__u32 ifa_rt_priority;
__be32 ifa_broadcast;
unsigned char ifa_scope;
unsigned char ifa_prefixlen;
__u32 ifa_flags;
char ifa_label[IFNAMSIZ];
/* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */
__u32 ifa_valid_lft;
__u32 ifa_preferred_lft;
unsigned long ifa_cstamp; /* created timestamp */
unsigned long ifa_tstamp; /* updated timestamp */
};
To make my answer more versatile, here is an abstract example (without binding to netfilter and skb devices logic):
struct in_ifaddr *ifa;
struct net_device *dev = dev_get_by_name(&init_net, "wlp7s0");
if(!dev) {
printk(KERN_ERR "Can't obtain device\n");
return;
}
// roughly
rcu_read_lock();
for(ifa = rcu_dereference(dev->ip_ptr->ifa_list);
ifa;
ifa = rcu_dereference(ifa->ifa_next))
printk("address: %pI4, mask: %pI4\n", &ifa->ifa_address, &ifa->ifa_mask);
rcu_read_unlock();
From example you can see that you can handle the whole chain(that #larsks mentioned in comment) depending on some specific logic.
P.S. don't forget to include <linux/netdevice.h> and <linux/inetdevice.h>.

cast multiple structs to a char string

this is my first time posting on stack overflow so be gentle. I am writing a networking program in c to run on linux machines. The goal of my program is to be able to capture packets sent to it, change the source ip and hw address, rebuild the packet with the new info and send it back out onto the wire. My question relates to the rebuilding process. I have some structs that I am using to hold information about various headers in my programs. Detailed here
struct my_ip
{
u_int8_t ip_vhl; /* header length, version */
#define IP_V(ip) (((ip)->ip_vhl & 0xf0) >> 4)
#define IP_HL(ip) ((ip)->ip_vhl & 0x0f)
u_int8_t ip_tos; /* type of service */
u_int16_t ip_len; /* total length */
u_int16_t ip_id; /* identification */
u_int16_t ip_off; /* fragment offset field */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_int8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */
u_int16_t ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
/* UDP header */
struct sniff_udp
{
u_short uh_sport; /* source port */
u_short uh_dport; /* destination port */
u_short uh_ulen; /* udp length */
u_short uh_sum; /* udp checksum */
};
#define SIZE_UDP 8 /* length of UDP header */
#define SIZE_ETHERNET 14
As well as a few other structs from the pcap library(like ether_header). I cast the u_char* to these structs like so
struct my_ip* ip = (struct my_ip*)(packet + sizeof(struct ether_header));
struct ether_header* eptr = (struct ether_header *) packet;
Where packet is a u_char holding the entirety of the packet
My question is, once I have modified data within these structures how do I cast all of my stucts back into a single u_char string? I am trying to cast each struct to fill a different segment of string in the same way a packet is structured
This is the code I have so far.
void buildPacket(sniff_udp *udp, ether_header *ethh, my_ip *ip, u_char *payload, u_char *buffer)
{
memset(buffer,0, (sizeof(udp)+sizeof(ethh)+sizeof(ip)+sizeof(payload)));
buffer=(u_char *)(ethh); // adds layer 2 header
(buffer+SIZE_ETHERNET)= (u_char *)ip; // adds layer 3 header
(buffer+SIZE_ETHERNET+sizeof(ip))=(u_char *) udp; // adds protocol header
(buffer+SIZE_ETHERNET+sizeof(ip)+SIZE_UDP)=(u_char *)payload; // adds payload
}
This isn't the correct way to do it from what I've gathered. How can I cast multiple structs to the same string?
Something like
(buffer+SIZE_ETHERNET)= (u_char *)ip; // adds layer 3 header
isn't valid because the lefthand operator of = won't be a (modifable) lvalue.
You can use memcpy() to copy contents of memory. The correct code should be like this:
void buildPacket(sniff_udp *udp, ether_header *ethh, my_ip *ip, u_char *payload, u_char *buffer)
{
memset(buffer,0, (sizeof(udp)+sizeof(ethh)+sizeof(ip)+sizeof(payload)));
memcpy(buffer, ethh, SIZE_ETHERNET); // adds layer 2 header
memcpy(buffer+SIZE_ETHERNET, ip, sizeof(ip)); // adds layer 3 header
memcpy(buffer+SIZE_ETHERNET+sizeof(ip), udp, SIZE_UDP); // adds protocol header
memcpy(buffer+SIZE_ETHERNET+sizeof(ip)+SIZE_UDP, payload, sizeof(payload)); // adds payload
}
This code doesn't seem correct because sizeof(udp), sizeof(ethh), sizeof(ip) and sizeof(payload) will return the size of pointers, not what is pointed, and I don't think it is what you want. Use correct size instead of them.

C structure alignment and network protocol headers

Solaris 10 SPARC
Sun Studio C compiler 12.3
On SPARC64 machines if you access a variable which isn't correctly aligned on the relevant 4 or 8 byte boundary, you will get a core dump. This requires the coder to jump through a few hoops to cope with this requirement, (but also makes you write portable code too).
If we have a C structure which models a network protocol header, (i.e. these 16 bits are a port, these 8 bits are the flags etc), if we then use alignment directives to suit a SPARC64 processor, will this still retain the byte mapping, or will everything break. Is there logic hiding the implementation of the byte storage from the layout of the struct.
typedef struct TCPHdr_
{
uint16_t th_sport; /**< source port */
uint16_t th_dport; /**< destination port */
uint32_t th_seq; /**< sequence number */
uint32_t th_ack; /**< acknowledgement number */
uint8_t th_offx2; /**< offset and reserved */
uint8_t th_flags; /**< pkt flags */
uint16_t th_win; /**< pkt window */
uint16_t th_sum; /**< checksum */
uint16_t th_urp; /**< urgent pointer */
} TCPHdr;
gets aligned like this:
typedef struct TCPHdr_
{
uint16_t th_sport __attribute__((aligned(8))); /**< source port */
uint16_t th_dport __attribute__((aligned(8))); /**< destination port */
uint32_t th_seq __attribute__((aligned(8))); /**< sequence number */
uint32_t th_ack __attribute__((aligned(8))); /**< acknowledgement number */
uint8_t th_offx2 __attribute__((aligned(8))); /**< offset and reserved */
uint8_t th_flags __attribute__((aligned(8))); /**< pkt flags */
uint16_t th_win __attribute__((aligned(8))); /**< pkt window */
uint16_t th_sum __attribute__((aligned(8))); /**< checksum */
uint16_t th_urp __attribute__((aligned(8))); /**< urgent pointer */
} TCPHdr;
Mostly it's a query about code like this:
SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(TCPHdr) + payload_len);
and
p1->tcph = (TCPHdr *)raw_tcp;
where the raw bytes are converted to the struct or a sizeof() tests the size of the struct. Will it still work or will the new struct not be able to map the network bytes?
You can cast an unaligned structure to its aligned version but data would be wrong. You need to put data to the right positions in memory manually. E.g. a function *unaligned_to_aligned* can copy data field by field. It can use unions to avoid core dumps.
When working with raw data from the network, take into account endianness. Network protocols and your platform can have different representation of numbers in memory and you may have to change the order of bytes in *int*s, *short*s etc.
For the record, here's the structs I'm using:
typedef struct TCPHdr_raw_ {
union {
uint16_t th_sport; /**< source port */
uint8_t th_sport8[2]; /**< source port */
} sport;
union {
uint16_t th_dport; /**< destination port */
uint8_t th_dport8[2]; /**< destination port */
} dport;
union {
uint32_t th_seq; /**< sequence number */
uint8_t th_seq8[4]; /**< sequence number */
} seq;
union {
uint32_t th_ack; /**< acknowledgement number */
uint8_t th_ack8[4]; /**< acknowledgement number */
} ack;
uint8_t th_offx2; /**< offset and reserved */
uint8_t th_flags; /**< pkt flags */
union {
uint16_t th_win; /**< pkt window */
uint8_t th_win8[2]; /**< pkt window */
} win;
union {
uint16_t th_sum; /**< checksum */
uint8_t th_sum8[2]; /**< checksum */
} sum;
union {
uint16_t th_urp; /**< urgent pointer */
uint8_t th_urp8[2]; /**< urgent pointer */
} urp;
} TCPHdr_raw;
typedef struct TCPHdr_
{
uint16_t th_sport __attribute__((aligned(8))); /**< source port */
uint16_t th_dport __attribute__((aligned(8))); /**< destination port */
uint32_t th_seq __attribute__((aligned(8))); /**< sequence number */
uint32_t th_ack __attribute__((aligned(8))); /**< acknowledgement number */
uint8_t th_offx2 __attribute__((aligned(8))); /**< offset and reserved */
uint8_t th_flags __attribute__((aligned(8))); /**< pkt flags */
uint16_t th_win __attribute__((aligned(8))); /**< pkt window */
uint16_t th_sum __attribute__((aligned(8))); /**< checksum */
uint16_t th_urp __attribute__((aligned(8))); /**< urgent pointer */
} TCPHdr;
and routines like this:
copy_raw_tcp_header(&(p->tcph), &tcph);
void copy_raw_tcp_header(TCPHdr *tcph, uint8_t *pktdata) {
TCPHdr_raw *raw_tcp_hdr = (TCPHdr_raw *)pktdata;
memcpy(&tcph->sport, &raw_tcp_hdr->sport.th_sport8, sizeof(uint16_t));
memcpy(&tcph->dport, &raw_tcp_hdr->dport.th_dport8, sizeof(uint16_t));
memcpy(&tcph->seq, &raw_tcp_hdr->seq.th_seq8, sizeof(uint32_t));
memcpy(&tcph->ack, &raw_tcp_hdr->ack.th_ack8, sizeof(uint32_t));
tcph->th_offx2 = raw_tcp_hdr->th_offx2;
tcph->th_flags = raw_tcp_hdr->th_flags;
memcpy(&tcph->th_win, &raw_tcp_hdr->win.th_win8, sizeof(uint16_t));
memcpy(&tcph->th_sum, &raw_tcp_hdr->sum.th_sum8, sizeof(uint16_t));
memcpy(&tcph->th_urp, &raw_tcp_hdr->urp.th_urp8, sizeof(uint16_t));
}
replace previous code like this:
p->tcph = &tcph;

Typedef an externel structure in file using cross-compiler (arm-none-eabi-gcc)

I'm trying to compile a project which consist of severel source fies & header files & includes some structure definiton. But when I compile an error comes
"error: expected specifier-qualifier-list before 'typedef'" in file "uip.h"
I have a structure in file named as "httpd.h"
struct httpd_state {
unsigned char timer;
struct psock sin, sout;
struct pt outputpt, scriptpt;
char inputbuf[50];
char filename[20];
char state;
struct httpd_fsdata_file_noconst *file;
int len;
char *scriptptr;
int scriptlen;
unsigned short count;
};
I want to typedef this structure in another file named as "uip.h"
struct uip_conn {
uip_ipaddr_t ripaddr; /**< The IP address of the remote host. */
u16_t lport; /**< The local TCP port, in network byte order. */
u16_t rport; /**< The local remote TCP port, in network order. */
u8_t rcv_nxt[4]; /**< The sequence number that we expect toreceive next. */
u8_t snd_nxt[4]; /**< The sequence number that was last sent by us. */
u16_t len; /**< Length of the data that was previously sent. */
u16_t mss; /**< Current maximum segment size for the connection. */
u16_t initialmss; /**< Initial maximum segment size for the connection. */
u8_t sa; /**< Retransmission time-out calculation state variable. */
u8_t sv; /**< Retransmission time-out calculation state variable. */
u8_t rto; /**< Retransmission time-out. */
u8_t tcpstateflags; /**< TCP state and flags. */
u8_t timer; /**< The retransmission timer. */
u8_t nrtx; /**< The number of retransmissions for the last segment sent*/
/** The application state. */
**typedef struct httpd_state uip_tcp_appstate_t;
uip_tcp_appstate_t appstate;**
} __attribute__((packed));
Can anyone please help??
You can't have a typedef statement inside a struct definition. Either hoist it outside of the struct, or don't use the typedef at all:
// Option #1: Hoisting
typedef struct httpd_state uip_tcp_appstate_t;
struct uip_conn {
...
uip_tcp_appstate_t appstate;
};
// Option #2: No typedef
struct uip_conn {
...
struct httpd_state appstate;
};

Resources