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>.
Related
I'm trying to write my own network packet filter module to replace iptables on my custom linux system.
I want the filter to drop all packets arriving from port 80 except the ones coming from the interface wlan0.
I hoped there would be a interface member in the struct iphdr but it seems to not be there (which makes sense since I think the interface is part of the 2nd layer). does anyone know how I can acheive this?
this is my code and I'm wandering what to put in the if statement that will complete the check:
static unsigned int pkg_filter_handler(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
if (!skb) {
return NF_ACCEPT;
}
/* check if loopback */
u32 srcAddr;
struct iphdr *ipHeader = ip_hdr(skb);
/* check if TCP protocol */
else if (iphdr->protocol == IPPROTO_TCP) {
/* check interface */
if (/*TODO: accept wlan0 rcp packets ad drop the rest*/) {
return NF_ACCEPT;
}
return NF_DROP;
}
return NF_ACCEPT;
}
I am using l2fwd-dpdk application from which I can extract 5-tuples, and can see if DNS Packet is present or not.
Now I want to classify the DNS Packet using dpdk, for which I am failing.
Here is my code.
struct rte_udp_hdr *udp_hdr;
struct dnshdr *dns_hdr;
if (rte_be_to_cpu_16(udp_hdr->dst_port) == 53)
{
printf("DNS Packet");
char *dns_hdr = (char *)udp_hdr + sizeof(rte_udp_hdr);
}
I want to separate
Flags
Rdata
Class
TTL
and save them separately. Is there any way around, I can comfortable to use cpp wrapper as well.
DPDK as of 21.08 does not house any header or structure to typecast to DNS packet. Hence easiest way to solve the issue as mentioned by #wildplasser is to declare your custom DNS header and use it. In your code snippet, you already have struct dnshdr *dns_hdr; So the easier way is to modify your existing code to reflect
struct rte_udp_hdr *udp_hdr;
struct dnshdr *dns_hdr;
/* use DPDK mtod API to get the start of ethernet frame */
/* check for packet size, ether type, IP protocol */
/* update udp_hdr to position in the packet */
if (rte_be_to_cpu_16(udp_hdr->dst_port) == 53)
{
printf("DNS Packet");
struct dnshdr *dns_hdr = (struct dnshdr *)((char *)udp_hdr + sizeof(rte_udp_hdr));
}
Note: Possible structure definition code snippet would be
typedef struct {
uint16_t id;
uint16_t rd:1;
uint16_t tc:1;
uint16_t aa:1;
uint16_t opcode:4;
uint16_t qr:1;
uint16_t rcode:4;
uint16_t zero:3;
uint16_t ra:1;
uint16_t qcount; /* question count */
uint16_t ancount; /* Answer record count */
uint16_t nscount; /* Name Server (Autority Record) Count */
uint16_t adcount; /* Additional Record Count */
} custom_dnshdr;
custom_dnshdr *dns_hdr = (custom_dnshdr *) ((char *)udp_hdr + sizeof(rte_udp_hdr));
I am taking a class on computer and network security. We are writing a packet spoofer. I could just download one from the internet and use it, but I prefer writing the stuff myself. Below is the struct that I use to represent the ip header which I am basing off of the wikipedia article. I am attempting to send an icmp ping packet. I have done it successfully, but only after assigning the value of the ip header length to the version field, and vice versa. Somehow I have setup my struct wrong, or I am assigning the values wrong, and I am not sure what I am doing incorrectly.
struct ip_header
{
uint8_t version : 4 // version
, ihl : 4; // ip header length
uint8_t dscp : 6 // differentiated services code point
, ecn : 2; // explicit congestion notification
uint16_t total_length; // entire packet size in bytes
uint16_t identification; // a unique identifier
uint16_t flags : 3 // control and identify fragments
, frag_offset : 13; // offset of fragment relative to the original
uint8_t ttl; // how many hops the packet is allowd to travel
uint8_t protocol; // what protocol is in use
uint16_t checksum; // value used to determine bad packets
uint32_t src_ip; // where the packet is form
uint32_t dest_ip; // where the packet is going
};
If I assign the version and ihl, like below, wireshark reports an error with the header, "Bogus IPV4 version (0, must be 4)".
char buffer[1024];
struct ip_header* ip = (struct ip_header*) buffer;
ip->version = 4;
ip->ihl = 5;
However, after changing to the following listing, the ICMP request goes through just fine.
char buffer[1024];
struct ip_header* ip = (struct ip_header*) buffer;
ip->version = 5;
ip->ihl = 4;
I have tried placing htons around the numbers, but that doesn't seem to do anything useful. What am I missing here?
You simply need to correct your structure's endianness. Look at the IP header structure defined in the <netinet/ip.h> file:
struct iphdr
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ihl:4;
unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
unsigned int version:4;
unsigned int ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif
uint8_t tos;
uint16_t tot_len;
uint16_t id;
uint16_t frag_off;
uint8_t ttl;
uint8_t protocol;
uint16_t check;
uint32_t saddr;
uint32_t daddr;
/*The options start here. */
};
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.
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;
};