Rohit
Rohit

Reputation: 1720

IP-address from sk_buff

I am writing a kernel module which registers a netfilter hook. I am trying to get the ip address of the caller by using the sk_buff->saddr member. Is there a way I can get the IP in human readable i.e. x.x.x.x format?

I found the function inet_ntop() but it doesn't seem to be available in kernel headers. How do I convert \xC0\xA8\x00\x01 to 192.168.0.1 ?

Upvotes: 12

Views: 15912

Answers (6)

4pie0
4pie0

Reputation: 29724

printk can handle this directly:

IPv4 addresses:

%pI4    1.2.3.4
%pi4    001.002.003.004
%p[Ii]4[hnbl]

For printing IPv4 dot-separated decimal addresses. The 'I4' and 'i4'
specifiers result in a printed address with ('i4') or without ('I4')
leading zeros.

The additional 'h', 'n', 'b', and 'l' specifiers are used to specify
host, network, big or little endian order addresses respectively. Where
no specifier is provided the default network/big endian order is used.

Passed by reference.

IPv6 addresses:

%pI6    0001:0002:0003:0004:0005:0006:0007:0008
%pi6    00010002000300040005000600070008
%pI6c   1:2:3:4:5:6:7:8

For printing IPv6 network-order 16-bit hex addresses. The 'I6' and 'i6'
specifiers result in a printed address with ('I6') or without ('i6')
colon-separators. Leading zeros are always used.

The additional 'c' specifier can be used with the 'I' specifier to
print a compressed IPv6 address as described by
http://tools.ietf.org/html/rfc5952

Passed by reference.

Reference: https://www.kernel.org/doc/Documentation/printk-formats.txt

Upvotes: 3

Cong Wang
Cong Wang

Reputation: 2049

You should use the %pI4 extended format specifiers provided by printk():

printk(KERN_DEBUG "IP addres = %pI4\n", &local_ip);

Upvotes: 17

anbhat
anbhat

Reputation: 427

There are two macros defined in include/linux/kernel.h

NIPQUAD for ipv4 addresses and NIP6 for ipv6 addresses.

#define NIPQUAD(addr) \
    ((unsigned char *)&addr)[0], \
    ((unsigned char *)&addr)[1], \
    ((unsigned char *)&addr)[2], \
    ((unsigned char *)&addr)[3]

#define NIP6(addr) \
    ntohs((addr).s6_addr16[0]), \
    ntohs((addr).s6_addr16[1]), \
    ntohs((addr).s6_addr16[2]), \
    ntohs((addr).s6_addr16[3]), \
    ntohs((addr).s6_addr16[4]), \
    ntohs((addr).s6_addr16[5]), \
    ntohs((addr).s6_addr16[6]), \
    ntohs((addr).s6_addr16[7])

There are ample examples in the kernel sources that make use of these to print ip addresses in human-readable format. For instance:

printk(KERN_DEBUG "Received packet from source address: %d.%d.%d.%d!\n",NIPQUAD(iph->saddr));

Hope this helps.

Upvotes: 13

Rohit
Rohit

Reputation: 1720

/* Convinience union to __be32 to ip address  */
union ip_address {
    u8 a[4];
    __be32 saddr;
};

IP Address could be obtained a[0].a[1].a[2].a[3]

Upvotes: 0

Yann Ramin
Yann Ramin

Reputation: 33177

Simple. The IP address in "x.x.x.x" format is called dotted-quad for a reason. Each number represents a byte, for a total of 4 bytes in your address.

So, with the 4 byte address, you would simply print the decimal value of each byte.

Quick and dirty example (replace printf with your output function of choice):

unsigned char *addr = (unsigned char*)sk_buff->addr;
printf("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);

Upvotes: 2

John Boker
John Boker

Reputation: 83709

You can use strtol to convert each piece to it's integer form.

Upvotes: 0

Related Questions