Neighbor solicitation sent instead of ICMP6 echo resquest - c

I'm trying to send an ICMPV6 echo request. Bellow my code:
struct icmp6_hdr icmp6;
int sock;
struct icmp6_filter filterv6;
struct ifreq ifr;
sock = socket(AF_INET6, SOCK_RAW,IPPROTO_ICMPV6);
ICMP6_FILTER_SETBLOCKALL(&filterv6);
ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &filterv6);
ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &filterv6);
ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &filterv6);
ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &filterv6);
ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filterv6);
ICMP6_FILTER_SETPASS(ND_REDIRECT, &filterv6);
setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filterv6, sizeof (filterv6));
...
setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof ifr);
...
icmp6.icmp6_type = ICMP6_ECHO_REQUEST;
icmp6.icmp6_code = 0;
icmp6.icmp6_cksum = 0;
icmp6.icmp6_id = id;
icmp6.icmp6_seq = 100;
if( (sendto(sock, &icmp6, sizeof(struct icmp6_hdr), 0, (struct sockaddr *)dest, socklen)) != sizeof(struct icmp6_hdr))
However, for an unknown reason, the sent packet is an NDS:
[root#jingo ~]# tcpdump -v -i any -s0 | grep icmp6
tcpdump: WARNING: Promiscuous mode not supported on the "any" device
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
11:57:08.397368 IP6 (hlim 255, next-header: ICMPv6 (58), length: 32) 2001:db8:0:85a3::ac1f:8003 > ff02::1:ff1f:8009: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has 2001:db8:0:85a3::ac1f:8009
11:57:09.397331 IP6 (hlim 64, next-header: ICMPv6 (58), length: 112) 2001:db8:0:85a3::ac1f:8003 > 2001:db8:0:85a3::ac1f:8003: [icmp6 sum ok] ICMP6, destination unreachable, length 112, unreachable address 2001:db8:0:85a3::ac1f:8009
I'm using 2.6.18-308.el5PAE kernel , Red Hat Enterprise Linux Server release 5.1 (Tikanga).

This is normal behavior.
Since you can't send IP traffic until you have the correct MAC address to direct packets to, something has to find that MAC address. In IPv4, you would have seen an ARP packet. NDP (neighbor discovery protocol) replaced ARP in IPv6, which is why you're seeing NDP traffic.
The real problem here is that the destination host is not reachable. It may be down, or the router may not know how to reach it. Your router might be configured incorrectly, but that seems unlikely.
Try pinging a host that is up, and you will see the NDP traffic followed by your ICMP echo request.

Related

ARP Response over router

I am pretty new to networking and I have been trying to understand ARP requests. I've been using mininet and wireshark in order to test what I'm doing.
When I use mininet to generate 2 hosts (h1 and h2) and a switch, my ARP broadcast is immediately responded with an ARP reply, everything works correctly.
When I use a given router.py script that generates the following on mininet -
*** Creating network
*** Adding controller
*** Adding hosts:
h1x1 h1x2 h2x1 h2x2 h3x1 h3x2 r0
*** Adding switches:
s1 s2 s3
*** Adding links:
(h1x1, s1) (h1x2, s1) (h2x1, s2) (h2x2, s2) (h3x1, s3) (h3x2, s3) (s1, r0) (s2, r0) (s3, r0)
*** Configuring hosts
h1x1 h1x2 h2x1 h2x2 h3x1 h3x2 r0
*** Starting controller
c0
*** Starting 3 switches
s1 s2 s3 ...
*** Routing Table on Router:
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
10.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 r0-eth3
172.16.0.0 0.0.0.0 255.240.0.0 U 0 0 0 r0-eth2
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 r0-eth1
// ./a.out Send <InterfaceName> <DestIP> <RouterIP> <Message>
mininet> h1x1 ./a.out Send h1x1-eth0 10.0.0.1 192.168.1.100 'This is a test'
This is how I run my command on mininet to run the ARP request.
When I try to run the ARP request using destination IP 10.0.0.1 and the router IP 192.168.1.00 my ARP request broadcasts normally, but I do not get the ARP reply, instead I get a series of ICMPv6 responses.
Here is how I am creating my ARP header
struct arp_hdr construstArpRequest(char if_name[], int sockfd, struct in_addr dst, struct ifreq if_hwaddr) {
printf("Constructing ARP request --\n");
struct arp_hdr arphdr;
arphdr.ar_hrd = htons(0x0001);
arphdr.ar_pro = htons(0x0800);
arphdr.ar_hln = 6;
arphdr.ar_pln = 4;
arphdr.ar_op = htons(0x0001);
unsigned long sip = get_ip_saddr(if_name, sockfd); // source IP
memcpy(arphdr.ar_sip, &sip, 4); // source IP
memcpy(arphdr.ar_tip, &dst.s_addr, 4); // taget IP
memset(arphdr.ar_tha, 0, 6); // taget HA
memcpy(arphdr.ar_sha, if_hwaddr.ifr_hwaddr.sa_data, 6); // source HA
return arphdr;
}
And I create my ARP request
int sockfd = -1;
if((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0){
perror("socket() failed!");
}
// connect to an internet frame
struct ifreq if_hwaddr;
memset(&if_hwaddr, 0, sizeof(struct ifreq));
strncpy(if_hwaddr.ifr_name, interfaceName, IFNAMSIZ-1);
if(ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr) < 0){
perror("SIOCGIFHWADDR");
}
struct arp_hdr arpRequest;
arpRequest = construstArpRequest(interfaceName, sockfd, router_ip, if_hwaddr);
If I need to include code about how I am actually sending the request, I can but not sure if it is necessary code. Throughout my research I have come across some answers saying that you will not get the broadcast response because you are running it over a network, it that's the case, how do you get the target MAC address?
ARP requests are for IPv4 only, and use broadcast (IPv6 does not have broadcast, and it uses NDP, not ARP), but routers do not forward broadcasts to a different network.
A source host will mask the destination address with its configured mask to determine if the destination address is on the same network. If the destination is on the same network, it will use ARP (either in the ARP table, or send a new ARP request) to determine the destination host data-link address and use that to build the data-link frame. If the destination is on a different network, the source host will use ARP (either in the ARP table, or send a new ARP request) to determine the data-link address of its configured gateway, and it will use the gateway data-link address to build the data-link frame.
You are trying to use an ARP request for a host on a different network, and that will not work. Trying to send an ARP request for a destination on a different network will get no response, and you are seeing that (you need to implement a timeout for your ARP requests, and send an error message up the network stack to the requesting process when it times out).
The IPv6 traffic you see is normal IPv6 maintenance traffic that periodically happens on a LAN where IPv6 is configured.

scapy send tcp packet on established connection

I have the following:
Server Side: TCP python server (not scapy)
Client Side: Scapy to establish connection and sent TCP packet
I am trying to send TCP packet via scapy on established connection after 3 way handshaking
I am able to build the 3 way handshaking and the server side (other side -python TCP server- not scapy- create TCP socket, bind, listen, accpet, recv()) shows new connection comes and accept() returns the created FD
I am trying to send packet from scapy after the 3 way handshake succeeded but recv() on the not-scapy side can't get the packet
scapy side:
#!/usr/bin/env python
from scapy.all import *
import time
# VARIABLES
src = sys.argv[1]
dst = sys.argv[2]
sport = random.randint(1024,65535)
dport = int(sys.argv[3])
# SYN
ip=IP(src=src,dst=dst)
SYN=TCP(sport=sport,dport=dport,flags='S',seq=1000)
SYNACK=sr1(ip/SYN)
# ACK
ACK=TCP(sport=sport, dport=dport, flags='A', seq=SYNACK.ack, ack=SYNACK.seq + 1)
send(ip/ACK)
time.sleep(15)
ip = IP(src=src, dst=dst)
tcp = ip / TCP(sport=sport, dport=dport, flags="PA", seq=123, ack=1) / "scapy packet 123"
tcp.show2()
send(tcp)
Not scapy side:
#!/usr/bin/python
import socket
from scapy.all import *
ip = sys.argv[1]
port = sys.argv[2]
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((ip, int(port)))
s.listen(1)
while True :
conn, addr = s.accept()
print 'Connection address:', addr
data = conn.recv(1024) # Stuck here .....
tcpdump output shows:
tcpdump: listening on ens1f1, link-type EN10MB (Ethernet), capture size 65535 bytes
18:09:35.820865 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto TCP (6), length 40)
11.4.3.31.63184 > 11.4.3.30.strexec-d: Flags [S], cksum 0x6543 (correct), seq 1000, win 8192, length 0
18:09:35.821017 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 44)
11.4.3.30.strexec-d > 11.4.3.31.63184: Flags [S.], cksum 0x748d (correct), seq 3017593595, ac k 1001, win 29200, options [mss 1460], length 0
18:09:35.930593 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto TCP (6), length 40)
11.4.3.31.63184 > 11.4.3.30.strexec-d: Flags [.], cksum 0xde5a (correct), seq 1, ack 1, win 8 192, length 0
18:09:51.057904 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto TCP (6), length 56)
11.4.3.31.63184 > 11.4.3.30.strexec-d: Flags [P.], cksum 0x8eef (correct), seq 4294966419:429 4966435, ack 1277373702, win 8192, length 16
18:09:51.057996 IP (tos 0x0, ttl 64, id 1194, offset 0, flags [DF], proto TCP (6), length 40)
11.4.3.30.strexec-d > 11.4.3.31.63184: Flags [.], cksum 0x8c4a (correct), seq 1, ack 1, win 2 9200, length 0
My question why receiver side is not getting the sent packet?
Note: My target to send TCP packet on established connection with bad checksum and receive it by not scapy tcp server
Thanks in advance!!
Your sequence numbers must accurately track the payload bytes you send. A packet with the SYN or FIN flag set is an exception and is treated as if it had a payload of length 1. In other words, you can use whatever initial sequence number you like, but then it must increase byte-for-byte with your sent payload (+1 for SYN or SYN+ACK [or FIN]).
So, if you start with a sequence number of 1000 in the SYN packet, then the next packet with payload (call this pktA) should have a sequence number of 1001. Then your next packet (pktB) should have sequence number 1001 + pktA.payload_size, and so forth.
Likewise, you cannot simply set the acknowledge number field in the TCP header to 1 (as you're doing with the "scapy packet 123"). Whenever you provide the ACK flag in the header, you need to acknowledge the other side's payload by setting the acknowledge number in the header to the last-received sequence number from the other side's last payload. In this case, you already sent a bare ACK packet with that acknowledge number, so you don't strictly need to include the ACK flag, but it's typical to always include it and if you are going to include the flag, the acknowledge sequence number should be set correctly.
See this link for a good overview:
http://packetlife.net/blog/2010/jun/7/understanding-tcp-sequence-acknowledgment-numbers/

Get Peer IP Address and Port

I manage to get the host information from particular requested network adapter using code below but i have no idea how to get peer ip address from host ip address.
struct sockaddr_in *sa = (struct sockaddr_in *)&item->ifr_addr;
ipAddr = ntohl(*((u_int32_t *)&sa->sin_addr));
if (pIpAddr != NULL)
{
*pIpAddr = ipAddr;
}
// Get the MAC address
if ( ioctl(s, SIOCGIFHWADDR, item) < 0 )
{
printf("_GetMacAddress : SIOCGIFHWADDR failed!\n");
return 0;
}
else
{
struct sockaddr *eth = (struct sockaddr *) &item->ifr_ifru.ifru_hwaddr;
unsigned long *low = (unsigned long *)&eth->sa_data[2];
unsigned short *high = (unsigned short*)&eth->sa_data[0];
//printf("%s : MAC = 0x%04x, 0x%08x", ntohs(*high), ntohl(*low));
printf("Interface %8s : IP %3d.%3d.%3d.%3d : MAC = %02x:%02x:%02x:%02x:%02x:%02x\n",
item->ifr_name,
((ipAddr >> 24)&0xff), ((ipAddr >> 16)&0xff), ((ipAddr >> 8)&0xff), (ipAddr&0xff),
((ntohs(*high)>> 8)&0x00ff), (ntohs(*high)&0x00ff),
((ntohl(*low)>> 24)&0x00ff), ((ntohl(*low)>> 16)&0x00ff), ((ntohl(*low)>> 8)&0x00ff), (ntohl(*low)&0x00ff));
if ((pMacHigh != NULL) && (pMacLow != NULL))
{
*pMacHigh = *high;
*pMacLow = *low;
}
}
The output is:
_GetMaxNetworkInterfaces 3
Interface lo : IP 127. 0. 0. 1 : MAC = 00:00:00:00:00:00
Interface enp4s0 : IP 192.168.128. 88 : MAC = f4:8e:38:ea:88:23
Interface wlp5s0 : IP 192.168. 53. 63 : MAC = b8:81:98:b7:71:90
If you are server listening for incoming connection, you can get peer address from accept() , in the second its argument, when a new socket is accepted
From man page of accept():
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
The argument addr is a pointer to a sockaddr structure. This structure is filled in with the address of the peer socket, as known to the communications layer. The exact format of the address returned addr is determined by the socket's address family (see socket(2) and the respective protocol man pages). When addr is NULL, nothing is filled in; in this case, addrlen is not used, and should also be NULL.
I have no idea how to get peer ip address from host ip address.
You can't. The question doesn't make sense.
To get a peer address you have to have a peer, and to have a peer you have to have a connected socket, with which you can call getpeername().
Or, if you're a server, you can get it as a side-effect of accept() via the second and third arguments.
I did tried to implement arp-scan to find the connected client Ip address.
First we have to define the max device connected for my case will be 32. I manage to get following information from previous code
Interface lo : IP 127. 0. 0. 1 : MAC = 00:00:00:00:00:00
Interface enp4s0 : IP 192.168.128. 88 : MAC = f4:8e:38:ea:88:23
Interface wlp5s0 : IP 192.168. 53. 63 : MAC = b8:81:98:b7:71:90
The information that require by arp-scan is interface name and the device IP address. In order to get client ip address we have to remove the character after counting the third dot. The end result we will get is:
127.0.0.
192.168.128.
192.168.53.
the last step is to loop for max device
127.0.0.0~31
192.168.128.0~31
192.168.53.0~31
Then feed into arp-scan ping and we will get the response from client ip address. I am using this arp-scan reference.

Why does my pc send more than 1514 byte packet in one go

I wrote a program to send 1460 byte data using TCP client and server continuously. My system interface MTU is 1500.
Here is my program of client
if((sockfd = socket(AF_INET, SOCK_STREAM, 0))< 0)
{
printf("\n Error : Could not create socket \n");
return 1;
}
setsockopt(sockfd,SOL_TCP,TCP_NODELAY,&one,sizeof(one));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(9998);
serv_addr.sin_addr.s_addr = inet_addr("10.10.12.1");
if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))<0)
{
printf("\n Error : Connect Failed \n");
return 1;
}
while(1)
{
write(sockfd, send_buff, 1448) ;
}
In wireshark initial 15 to 30 packets are showing that 1514 byte of packet is going but afterwards showing as below
wireshark output of some packet
No. Time Source Destination Protocol Length Info
16 0.000000 10.10.12.2 10.10.12.1 TCP 5858 53649 > distinct32 [ACK] Seq=3086892290 Ack=250285353 Win=14608 Len=5792 TSval=23114307 TSecr=23833274
Frame 16: 5858 bytes on wire (46864 bits), 5858 bytes captured (46864 bits)
Ethernet II, Src: 6c:3b:e5:14:9a:a2 (6c:3b:e5:14:9a:a2), Dst: Ibm_b5:86:85 (00:1a:64:b5:86:85)
Internet Protocol Version 4, Src: 10.10.12.2 (10.10.12.2), Dst: 10.10.12.1 (10.10.12.1)
Version: 4
Header length: 20 bytes
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))
Total Length: 5844
Identification: 0x8480 (33920)
Flags: 0x00
Fragment offset: 0
Time to live: 64
Protocol: TCP (6)
Header checksum: 0xb38d [correct]
Source: 10.10.12.2 (10.10.12.2)
Destination: 10.10.12.1 (10.10.12.1)
Transmission Control Protocol, Src Port: 53649 (53649), Dst Port: distinct32 (9998), Seq: 3086892290, Ack: 250285353, Len: 5792
Source port: 53649 (53649)
Destination port: distinct32 (9998)
[Stream index: 0]
Sequence number: 3086892290
[Next sequence number: 3086898082]
Acknowledgement number: 250285353
Header length: 32 bytes
Flags: 0x010 (ACK)
Window size value: 913
[Calculated window size: 14608]
[Window size scaling factor: 16]
Checksum: 0x42dd [validation disabled]
Options: (12 bytes)
No-Operation (NOP)
No-Operation (NOP)
Timestamps: TSval 23114307, TSecr 23833274
Data (5792 bytes)
On wireshark it is showing that more than 5792, 7000, 65535 byte of packet are going.
But i am sending 1514 byte of packet in one go. on other side i am receiving 1514 byte of packets only due to network mtu.
So my question is
why this much of huge packets are going ?
I tried without NODELAY option also but it is not working.
Is there any solution to send particular packet size (such as 1514 byte) can be send, no jumbo frames ?
I update my tcp_rmem and tcp_wmem also for tcp sending buffer and receiving buffer also. But did not found any solution.
TCP, by design, bundles up multiple write() calls into larger packets. Also, TCP coalesces packets by default according to Nagle's Algorithm.
If you want more control over the actual size of network packets, use UDP.
These are "jumbo frames", and they're faster than traditional frame sizes because they don't load up a CPU as much.
Consider yourself fortunate that you're getting them without futzing around with your IP stack's settings.
I searched a lot and found that, we need to change some parameter on interface.
On my interface eth0 default option are
Offload parameters for eth0:
rx-checksumming: on
tx-checksumming: on
scatter-gather: on
tcp-segmentation-offload: on
udp-fragmentation-offload: off
generic-segmentation-offload: on
generic-receive-offload: on
large-receive-offload: off
rx-vlan-offload: on
tx-vlan-offload: on
ntuple-filters: off
receive-hashing: off
now using ethtool we need to off some sending side segementation offload.
For that
sudo ethtool -K eth0 tso off gso off
using this
Offload parameters for eth0:
rx-checksumming: on
tx-checksumming: on
scatter-gather: on
tcp-segmentation-offload: off
udp-fragmentation-offload: off
generic-segmentation-offload: off
generic-receive-offload: on
large-receive-offload: off
rx-vlan-offload: on
tx-vlan-offload: on
ntuple-filters: off
receive-hashing: off
After this your interface will send packets whatever you want to send.

Filtering packets in pcap dump file

I'm writing network analyzer and I need to filter packets saved in file, I have written some code to filter http packets but I'm not sure if it work as it should because when I use my code on a pcap dump the result is 5 packets but in wireshark writing http in filter gives me 2 packets and if I use:
tcpdump port http -r trace-1.pcap
it gives me 11 packets.
Well, 3 different results, that's a little confusing.
The filter and the packet processing in me code is:
...
if (pcap_compile(handle, &fcode, "tcp port 80", 1, netmask) < 0)
...
while ((packet = pcap_next(handle,&header))) {
u_char *pkt_ptr = (u_char *)packet;
//parse the first (ethernet) header, grabbing the type field
int ether_type = ((int)(pkt_ptr[12]) << 8) | (int)pkt_ptr[13];
int ether_offset = 0;
if (ether_type == ETHER_TYPE_IP) // ethernet II
ether_offset = 14;
else if (ether_type == ETHER_TYPE_8021Q) // 802
ether_offset = 18;
else
fprintf(stderr, "Unknown ethernet type, %04X, skipping...\n", ether_type);
//parse the IP header
pkt_ptr += ether_offset; //skip past the Ethernet II header
struct ip_header *ip_hdr = (struct ip_header *)pkt_ptr;
int packet_length = ntohs(ip_hdr->tlen);
printf("\n%d - packet length: %d, and the capture lenght: %d\n", cnt++,packet_length, header.caplen);
}
My question is why there are 3 different result when filtering the http? And/Or if I'm filtering it wrong then how can I do it right, also is there a way to filter http(or ssh, ftp, telnet ...) packets using something else than the port numbers?
Thanks
So I have figured it out. It took a little search and understanding but I did it.
Wireshark filter set to http filter packets that have set in tcp port 80 and also flags set to PSH, ACK. After realizing this, the tcpdump command parameters which result in the same numbers of packets was easy to write.
So now the wireshark and tcpdump gives the same results
What about my code? well I figured that I actually had an error in my question, the filter
if (pcap_compile(handle, &fcode, "tcp port 80", 1, netmask) < 0)
indeed gives 11 packets (src and dst port set to 80 no matter what tcp flags are)
Now to filter the desired packets is a question of good understanding the filter syntax
or setting to filter only port 80 (21,22, ...) and then in callback function or in while loop get the tcp header and from there get the flags and use mask to see if it is the correct packet (PSH, ACK, SYN ...) the flags number are for example here

Resources