Why can't I capture raw packet even though tcpdump can? - c

I'm trying to capture port-mirroring packets using raw socket (skipped error checking to show only main code):
int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
int size = recvfrom(sock, buf, 65536, 0, &saddr, &saddr_size);
struct iphdr* iph = (struct iphdr*)(buf + sizeof(struct ethhdr));
if (iph->protocol != 6 || iph->saddr != inet_addr("192.168.12.48")) return;
printf("got it\n");
Although tcpdump can capture the packets, my program can't. Here's a dump of a packet:
22:19:42.140498 IP (tos 0x0, ttl 54, id 42987, offset 0, flags [DF], proto TCP (6), length 52)
192.168.12.48.33011 > 172.16.103.12.57102: Flags [.], cksum 0xf4ef (correct), ack 7, win 186, options [nop,nop,TS val 1950796524 ecr 3768292988], length 0
0x0000: 4500 0034 a7eb 4000 3606 bce3 c0a8 0c30 E..4..#.6......0
0x0010: ac10 670c 80f3 df0e 983d f043 d1c7 3087 ..g......=.C..0.
0x0020: 8010 00ba f4ef 0000 0101 080a 7446 caec ............tF..
0x0030: e09b 967c ...|
I'm using CentOS 6.5 kernel 2.6.32-431.29.2.el6.x86_64. I already disabled firewall and set rp_filter to 0. Does anyone know how to capture such packets in C?

Related

Same IP Addresses while capturing Packets under Linux (C Program)

I am receiving network packets by writing a code in c. So far I am receiving packets correctly but the only problem I'm facing is that I'm having same IP addresses for Ethernet, TCP and UDP. i'm not having any trouble while receiving via tcpdump.
Ethernet source of my system is: b0:10:41:fc:d7:2f
And IP address of my interface is: 192.168.10.145
These are received packets:
162 >>> Received packet with 66 bytes: Ethernet src:
b0:10:41:fc:d7:2f dst: b0:10:41:fc:d7:2f type: 0x800 IP version: 4
ihl: 5 ttl: 64 protocol: 6 src: 192.168.10.145 dst 192.168.10.145 TCP
src: 46888 dst: 80 seq: 3048209837 win: 4508 ACK 000000: b728 0050
b5af fdad 0e1d 21a1 8010 119c .(.P......!..... 0x0010: e258 0000
0101 080a 5a05 1f81 0595 4669
163 >>> Received packet with 66 bytes: Ethernet src:
b0:10:41:fc:d7:2f dst: b0:10:41:fc:d7:2f type: 0x800 IP version: 4
ihl: 5 ttl: 64 protocol: 6 src: 192.168.10.145 dst 192.168.10.145 TCP
src: 38836 dst: 443 seq: 1969857171 win: 341 ACK 000000: 97b4 01bb
7569 a293 0473 15bc 8010 0155 ....ui...s.....U 0x0010: 11f1 0000
0101 080a 4011 29b5 45f5 c4da
164 >>> Received packet with 1024 bytes: Ethernet src:
0:1a:a0:3f:d6:fc dst: 0:1a:a0:3f:d6:fc type: 0x800 IP version: 4 ihl:
5 ttl: 64 protocol: 6 src: 110.93.233.24 dst 110.93.233.24 TCP src:
80 dst: 46888 seq: 236790177 win: 595 ACK 000000: 0050 b728 0e1d
21a1 b5af fdad 8010 0253 .P.(..!........S 0x0010: 6e5f 0000 0101
080a 0595 46a1 5a05 199a n_........F.Z... 0x0020: f107 eb73 1b82
1492 c88f e84c 101a 9416 ...s.......L.... 0x0030: 9a27 900f 2020
1985 836f 79d5 8a26 15fa .'.. ...oy..&..
And this is my code:
layer2: {
struct ethhdr *eth = (struct ethhdr*) data;
printf("\tEthernet src: %s dst: %s type: %#04x\n",
ether_ntoa((const struct ether_addr*) eth->h_source),
ether_ntoa((const struct ether_addr*) eth->h_dest),
ntohs(eth->h_proto)
);
protocol = ntohs(eth->h_proto);
next_hdr = (char *) (eth + 1);}
layer3: switch (protocol) {
case ETH_P_IP: {
/* Parse IP protocol */
struct iphdr *ip = (struct iphdr*) next_hdr;
char buf[32];
printf("\tIP version: %u ihl: %u ttl: %u protocol: %u src: %s dst %s\n",
ip->version,
ip->ihl,
ip->ttl,
ip->protocol,
inet_ntop(AF_INET, &ip->saddr, buf, sizeof(buf)),
inet_ntop(AF_INET, &ip->daddr, buf, sizeof(buf))
);
What am I doing wrong ?
You're using the same buf to hold both IP addresses:
inet_ntop(AF_INET, &ip->saddr, buf, sizeof(buf)),
inet_ntop(AF_INET, &ip->daddr, buf, sizeof(buf))
Because you're using the same buffer, and both calls to inet_ntop() are done before the call to printf(), the last call to inet_ntop() will overwrite the results from the first call.
If following the first Advise, wouldn't work. Maybe you need a Buffer for Ethernet too ?
E.g.
struct ethhdr *eth = (struct ethhdr *)Buffer;
and get the Data with
eth->h_dest[0] , eth->h_dest[1] , eth->h_dest[2] , eth->h_dest[3] , eth->h_dest[4] , >eth->h_dest[5]
?

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/

How can I send an HTTP response using Linux raw sockets in c

Lately I have been trying to code a webserver using linux raw sockets in c, for the point of education. If my understanding is correct, this is how the ideal server should act:
| [SYN] |
|<--------------|
| [SYN] [ACK] |
|-------------->|
| [ACK] |
|<--------------|
|GET / HTTP/1.1 |
|<--------------|
| [ACK] |
|-------------->|
Server |HTTP/1.1 200 OK| Client
|-------------->|
| [ACK] |
|<--------------|
| [FIN] [ACK] |
|<--------------|
| [FIN] [ACK] |
|-------------->|
| [ACK] |
|<--------------|
| [ACK] |
|-------------->|
However, trying to actually implememt this is a lot harder than it looks. Right now, I have code that can get up to the acknowledgement to the HTTP request without any problems. However, I cannot find anywhere on the internet that explains how to send the actual response. I have tried so many things, but nothing I can find will work. Here is how I am filling out the packet:
//allocate a packet to send:
uint8_t* httppack=(uint8_t*)malloc(IP_MAXPACKET*sizeof(uint8_t));
//allocate and fill out the payload:
char* payload=malloc(100*sizeof(char));
payload="HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n<!doctype html><html><head><title>Evan's Webpage</title></head><body><h1>Evan's Webpage</h1></body></html>\r\n";
int payloadlen=strlen(payload);
//IP header
struct ip* iph=(struct ip*)httppack;
iph->ip_hl = 20/sizeof(uint32_t);
iph->ip_v = 4;
iph->ip_tos = 0;
//Flags: none set
iph->ip_off = htons ((0 << 15) + (0 << 14) + (0 << 13) + 0);
iph->ip_ttl = 255;
iph->ip_p = IPPROTO_TCP;
if (inet_pton (AF_INET, "192.168.1.141", &(iph->ip_src)) != 1) {
printf("Failed to convert source IP to network form\n");
exit (EXIT_FAILURE);
}
if (inet_pton (AF_INET, "192.168.1.114", &(iph->ip_dst)) != 1) {
printf("Failed to convert target IP to network form\n");
exit (EXIT_FAILURE);
}
//Since we don't know the checksum yet, make it zero:
iph->ip_sum = 0;
//Length is IP header (20) + TCP header (no options, 20) and payload
iph->ip_len = htons (20+20+payloadlen);
//ID is 2 because it is the third packet being sent (first was 0)
iph->ip_id = htons (2);
//IP Checksum function (I did not include it in this example, just assume that it works)
iph->ip_sum = chksm ((uint16_t *)iph, 20);
//TCP header
struct tcphdr* tcph=(struct tcphdr*)(httppack+sizeof(struct ip));
//source: http
tcph->source = htons (80);
//reserved: 0
tcph->res1 = 0;
//TCP header size: 20 (no options)
tcph->doff = 20/4;
tcph->rst = 0;
tcph->urg = 0;
tcph->res2 = 0;
//Window: max size
tcph->window = htons (65535);
tcph->urg_ptr = htons (0);
//We dont know what port the client will be requesting from at first. receivetcph is the TCP header of the last packet we received (HTTP request) so the dest port will be wherever that packet was sent from
tcph->dest = receivetcph->source;
// The sequence will simply be whatever the last packet's ack sequence was (Which will be 1)
tcph->seq = receivetcph->ack_seq;
//The acknowledgement sequence is the HTTP request packet's sequence (htseq) + the amount of data we received - ethernet header - IP header - TCP header (rsize). I am fairly confident this is not the problem with my code, so assume that it works
tcph->ack_seq = htonl(htseq+rsize);
//TCP Flags: ACK and PSH
tcph->syn = 0;
tcph->fin = 0;
tcph->ack = 1;
tcph->psh = 1;
//Another Checksum function, again, just assume it works
tcph->check = tcpchksm (*cip, *ctcp, (uint8_t*)payload, payloadlen);
//Copy payload to buffer before we send
memcpy((httppack+20+20), payload, payloadlen*sizeof(uint8_t));
But obviously this is wrong because the client does not acknowledge this packet when I send it, in fact it acts exactly as if I did not send the packet at all.
Questions:
-What is the correct way to fill out the HTTP response packet?
-What were the errors to the way I was filling it out?
-Finally, any advice about my code is appreciated (EXCEPT ADVICE TELLING ME TO STAY AWAY FROM RAW SOCKETS!!)
EDIT:
One last detail: when you use wire shark to sniff an http response being sent between a server and a client, it identifies the packet with an HTTP protocol, instead of a TCP protocol. I'd does not identify my packet as an HTTP protocol, and calls it a segment of a reassembled PDU. hopefully this will help you with question 2.
Thanks in advance

Neighbor solicitation sent instead of ICMP6 echo resquest

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.

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.

Resources