Printable IPv6 address and port from struct inet_sock - linux

Do you know any way to print in readable format an ipv6 address and its port from the inet_sock struct?
My question has two parts. One is which are the structure members that have this information and the second is how to print them in readable format.
Thanks!

printk has new modifiers which help printing inet addresses (I think since kernel 2.6.24). So you can try several ways, as an example:
//destination address
printk("%pI6 %d\n", my_inet_socket->pinet6->daddr,
ntohs(my_inet_socket->inet_dport));
//source address
printk("%pI6 %d\n", my_inet_socket->pinet6->saddr,
ntohs(my_inet_socket->inet_sport));
Here's how many modifiers you have and how they print the IPv6 address. You can check http://www.kernel.org/doc/Documentation/printk-formats.txt for more info.
%pI6 0001:0002:0003:0004:0005:0006:0007:0008
%pi6 00010002000300040005000600070008
%pI6c 1:2:3:4:5:6:7:8
For older kernels you need to use NIP6 like this:
//destination address
printk(NIP6_FMT " %d\n", NIP6(my_inet_socket->pinet6->daddr),
ntohs(my_inet_socket->inet_dport));
//source address
printk(NIP6_FMT " %d\n", NIP6(my_inet_socket->pinet6->saddr),
ntohs(my_inet_socket->inet_sport));
As a last note, you can check net/ipv6/tcp_ipv6.c from the kernel itself. It has tons of examples. Hope this helps you

Related

converting an address from a char type to a ip6addr in Contiki-NG

I'm sending an IPV6 address in a packet data section, that is beside the sender and receiver addresses.
I did convert it to a char using uiplib_ipaddr_snprint() and added it to the package and sent it.
Everything is working perfectly, I managed to cut the address from the data, however, I'm having trouble converting it using uiplib_ip6addrconv() but when I try to print the address is empty!
I'm not sure where the error is, but in regards to string manipulations I think everything is working correctly, the address is printed in the string form correctly, however, the converting doesn't seem to be working and I'm not sure why, any help is appreciated it.
This is how I get the address from the data of the packet, and p contains the correct address, then try to convert it to an ip6addr where things doesn't work.
Thank you.
int size = 40;
char *p;
p = strstr(str,"fe");
printf("%s\n", p);
const uip_ip6addr_t *addr_2;
uiplib_ip6addrconv(p, addr_2);

C Socket - captured packets have same ip_dst and ip_src

I'm using C SOCK_RAW socket to capture incoming packets on my machine (192.168.0.16), when trying to display some fields of the IP packet captured, everything is correct (TTLs, length, etc...), except that my ip_dst and ip_src are... the same ! (in fact the ip_dst seems to have been overwritten at some point...
The structure of the code used:
sockfd = socket (AF_INET, SOCK_RAW, IPPROTO_TCP))
recvfrom(sockfd, buffer, IP_MAXPACKET, 0, &from, &fromlen)
...
struct ip iphdr; //and then copying the right section of "buffer" into it...
printf("Source: %s - Dest: %s \n",inet_ntoa(iphdr.ip_src),inet_ntoa(iphdr.ip_dst));
Displays:
Source: 192.168.0.5 - Dest: 192.168.0.5
while i can see (from Wireshark) that the real destination is 192.168.0.16 (which is indeed a VM running on 192.168.0.5 - in case that could explain this weird phenomenenon).
Thanks for helping me to understand this !
EDIT: this (listening) program is running on the VM (192.168.0.16)
according to the inet_ntoa manual:
The inet_ntoa() function converts the Internet host address in, given in network byte order, to a string in IPv4 dotted-decimal notation.
The string is returned in a statically allocated buffer, which subsequent calls will overwrite.
Which means every time you call this function, the results will be overwritten to the same address. so to keep the result somewhere else, you need to copy it into some buffer using something like strcpy.
char src[15], dst[15];
strcpy(src, inet_ntoa(iphdr.ip_src));
strcpy(dst, inet_ntoa(iphdr.ip_dst));
printf("Source: %s - Dest: %s \n", src, dst);
Note: this answer is solely for the those who comes here through a search result since this post is really old.

wireless sniffing using pcap, MAC address filter

I am writing a wireless packet sniffer program in C. I have set my wireless interface in monitor mode using airmon-ng, and now i am sniffing on the interface "mon0". I am using linux(ubuntu 10.10).
I want to set MAC address as the filter for the packets.
I have done it as shown below, but it says
"mon0 no IPV4 address assigned"
pcap_lookupnet(dev,&net,&mask,errbuf);
printf("%s\n",errbuf);
/* Open the session in promiscuous mode */
handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
if (handle == NULL) {
printf("Couldn't open device %s: %s\n", dev, errbuf);
return 2;
}
if(pcap_compile(handle,&fp,argv[0],0,net)==-1){
fprintf(stderr,"Error calling pcap_compile\n");exit(1);}
if(pcap_setfilter(handle,&fp) == -1){
fprintf(stderr,"Error setting filter\n");exit(1);}
/* The call pcap_loop() and pass our callback function */
pcap_loop(handle, 10, my_callback, NULL);
Please help me, how i can set the filter for MAC address??
"no IPV4 address assigned" is an error from pcap_lookupnet(). All it means is that the network interface on which you're trying to capture does not have an IPv4 address assigned to it. What airmon-ng did was to create a "monitor" interface for the Wi-Fi adapter; the regular network interface for the adapter might have an IP address assigned to it, but the monitor interface won't have one.
The only place where the IP address matters is for ip broadcast filter expressions; if you're not filtering for IPv4 broadcast addresses, which you probably won't be, there's no need to get the IPv4 address. To quote the pcap_compile() man page:
If the netmask of the network on which packets are being captured isn't known to the program, or if packets are being captured on the Linux "any" pseudo-interface that can capture on more than one network, a value of 0 can be supplied; tests for IPv4 broadcast addreses won't be done correctly, but all other tests in the filter program will be OK.
so just pass 0 as the "net" argument to pcap_compile().
If you want to search for packets being sent to a particular MAC address, you can just use wlan dst XX:XX:XX:XX:XX:XX; if you want to search for packets being sent from a particular MAC address, you can just use wlan src XX:XX:XX:XX:XX:XX; if you want to search for packets being sent to or from a particular MAC address, you can just use wlan host XX:XX:XX:XX:XX:XX. If you care about the access point address, rather than the station address, you'll need to use filters such as wlan ra XX:XX:XX:XX:XX:XX or wlan ta XX:XX:XX:XX:XX:XX, at least with newer versions of libpcap. (See the pcap-filter man page or, if you don't have a pcap-filter man page, the tcpdump man page for details.)

Get starting address of a memory page in Linux

In my code, I need to keep track of some pages which are being modified. Initially I give only read access to them, but on the signal handler I give them both read and write access (I am not going to explain what is the purpose for all that and there is actually more code in the signal handler, which I've not shown).
Now my question is how to get the starting address of a page from a memory address which resides in that page. So basically I need to implement the get_page_start_addr shown here in the code. Up till now, I was only doing it for a single page, whose starting address my program knew. But now, since I need to do it for multiple pages, I need to get the starting address of the page from any arbitrary memory address, because mprotect only accepts starting page address as valid argument.
static void memory_change_handler(int sig, siginfo_t *si, void *unused)
{
long addr = (long)si->si_addr;
long page_start_addr = get_page_start_addr( addr );
if (mprotect((void*)page_start_addr, pagesize, PROT_READ | PROT_WRITE) == -1)
{
print_error();
handle_error("mprotect");
}
}
In Linux (in other OSes too, I guess), pages are aligned at page boundaries. Thus, if you know your PAGE_SIZE, then you can simply get the start of the page by masking the lower address bits.
page_start = addr & ~(PAGE_SIZE-1);
To portably know your pagesize, use sysconf(_SC_PAGESIZE).
You can take that address (unsigned long) /pagesize and *pagesize.
This gives you the first page address of your logical address.

linux raw ethernet socket bind to specific protocol

I'm writing code to send raw Ethernet frames between two Linux boxes. To test this I just want to get a simple client-send and server-receive.
I have the client correctly making packets (I can see them using a packet sniffer).
On the server side I initialize the socket like so:
fd = socket(PF_PACKET, SOCK_RAW, htons(MY_ETH_PROTOCOL));
where MY_ETH_PROTOCOL is a 2 byte constant I use as an ethertype so I don't hear extraneous network traffic.
when I bind this socket to my interface I must pass it a protocol again in the socket_addr struct:
socket_address.sll_protocol = htons(MY_ETH_PROTOCOL);
If I compile and run the code like this then it fails. My server does not see the packet. However if I change the code like so:
socket_address.sll_protocol = htons(ETH_P_ALL);
The server then can see the packet sent from the client (as well as many other packets) so I have to do some checking of the packet to see that it matches MY_ETH_PROTOCOL.
But I don't want my server to hear traffic that isn't being sent on the specified protocol so this isn't a solution. How do I do this?
I have resolved the issue.
According to http://linuxreviews.org/dictionary/Ethernet/ referring to the 2 byte field following the MAC addresses:
"values of that field between 64 and 1522 indicated the use of the new 802.3 Ethernet format with a length field, while values of 1536 decimal (0600 hexadecimal) and greater indicated the use of the original DIX or Ethernet II frame format with an EtherType sub-protocol identifier."
so I have to make sure my ethertype is >= 0x0600.
According to http://standards.ieee.org/regauth/ethertype/eth.txt use of 0x88b5 and 0x88b6 is "available for public use for prototype and vendor-specific protocol development." So this is what I am going to use as an ethertype. I shouldn't need any further filtering as the kernel should make sure to only pick up ethernet frames with the right destination MAC address and using that protocol.
I've worked around this problem in the past by using a packet filter.
Hand Waving (untested pseudocode)
struct bpf_insn my_filter[] = {
...
}
s = socket(PF_PACKET, SOCK_DGRAM, htons(protocol));
struct sock_fprog pf;
pf.filter = my_filter;
pf.len = my_filter_len;
setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof(pf));
sll.sll_family = PF_PACKET;
sll.sll_protocol = htons(protocol);
sll.sll_ifindex = if_nametoindex("eth0");
bind(s, &sll, sizeof(sll));
Error checking and getting the packet filter right is left as an exercise for the reader...
Depending on your application, an alternative that may be easier to get working is libpcap.

Resources