I'm implementing packet collector, but I suffer from packet drops.
My binary can get most of packets from some specific IP region. (Ex. 100.101.1.1, 100.101.2.1). But to some specific IP region, I cannot get any packet. (Ex. 200.201.1.1, 200.201.2.1)
At that time, tcpdump can get packets from any IP regions.
My pcap code snippet from my implementation is followings:
struct bpf_program fp;
pcap_t *pcd;
char errbuf[PCAP_ERRBUF_SIZE];
bpf_u_int32 netp;
char port[16], dev[16];
......
pcd = pcap_open_live(dev, BUFSIZ, PROMISCUOUS, -1, errbuf);
pcap_compile(pcd, &fp, port, 0, netp);
pcap_setfilter(pcd, &fp);
while(1){
packet = pcap_next(pcd, &hdr);
}
Is there any idea for me?
Since you mentioned that you can get all the ip packets on the interface using tcpdump, I would consider the following line in your code is all right as long as you are using the same interface name for the parameter dev as you use for tcpdump.
pcap_open_live(dev, BUFSIZ, PROMISCUOUS, -1, errbuf);
The issue might be in the line,
pcap_compile(pcd, &fp, port, 0, netp);
In the above line, port variable is a filter string. Your packet collector will only collect the packets that passes this filter. If you are not using proper filter parameters in your port string to allow also the packets involving ip addresses 200.201.x.x, you will not capture them.
Related
I am trying to send and receive raw ethernet frames to include a network device as a media access controller in a simulation environment.
Therefore it is important that the receiving of the packets works through nonblocking statements.
Now the sending of the raw ethernet frames works fine but there's one thing about the receive path that is confusing me:
How do I know where the one frame ends and the other frame begins.
What I fundamentally do is to open a raw socket:
device.socket = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
setting it up as non blocking:
flags = fcntl(s,F_GETFL,0);
assert(flags != -1);
fcntl(s, F_SETFL, flags | O_NONBLOCK);
and then call the recv() function cyclical to get the data from the socket:
length = recv(s, buffer, ETH_FRAME_LEN_MY, 0);
But as far as I know the recv() function only returns the amount of bytes, that is currently availible in the receive buffer and therefore I do not know if another frame starts or if I am still reading the "old" packet.
And because of the fact, that the length of the ethernet frame is not included in the header I can not do this on my own.
Thank you in advance!
If anyone runs into the same problem here's a possible solution:
You can use the libpcap library(in windows winpcap) to open the device as a capture device:
char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */
Pcap_t *handle; /* packet capture handle */
/* open capture device*/
/* max possible length, not in promiscous mode, no timeout!*/
handle = pcap_open_live(dev, 65536, 0, 0, errbuf);
if (handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
}
/* set capture device to non blocking*/
if(pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf)){
fprintf("Could not set pcap interface in non blocking mode: %s \n", errbuf);
}
Now you can cyclic call the pcap_dispatch function to receive packet(s):
int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
You have to provide a callback function in which the data is handled.
See https://www.freebsd.org/cgi/man.cgi?query=pcap_dispatch&apropos=0&sektion=3&manpath=FreeBSD+11-current&format=html for further information.
You can send raw ethernet frames by using the inject function:
pcap_inject(pcap,frame,sizeof(frame));
I have a forking HTTP proxy implemented on my Ubuntu 14.04 x86_64 with the following scheme (I'm reporting the essential code and pseudocode just to show the concept):
socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bind(socketClient,(struct sockaddr*)&addr, sizeof(addr));
listen(socketClient, 50);
newSocket = accept(socketClient, (struct sockaddr*)&cliAddr, sizeof(cliAddr));
get request from client, parse it to resolve the requested hostname in an IP address;
fork(), open connection to remote server and deal the request;
child process: if it is a GET request, send original request to server and while server is sending data, send data from server to client;
child process: else if it is a CONNECT request, send string 200 ok to client and poll both client socket descriptor and server socket descriptor with select(); if I read data from server socket, send this data to client; else if I read data from client socket, send this data to server.
The good thing is that this proxy works, the bad thing is that now I must collect statistics; this is bad because I'm working on a level where I can't get the data I'm interested in. I don't care about the payload, I just need to check in IP and TCP headers the flags I care about.
For example, I'm interested in:
connection tracking;
number of packets sent and received.
As for the first, I would check in the TCP header the SYN flag, SYN/ACK and then a last ACK; as for the second, I would just do +1 to a counter of mine every time a char buffer[1500] is filled with data when I send() or recv() a full packet.
I realized that this is not correct: SOCK_STREAM doesn't have the concept of packet, it is just a continuous stream of bytes! The char buffer[1500] I use at point 7. and 8. has useful statistic, I may set its capacity to 4096 bytes and yet I couldn't keep track of the TCP packets sent or received, because TCP has segments, not packets.
I couldn't parse the char buffer[] looking for SYN flag in TCP header either, because IP and TCP headers are stripped from the header (because of the level I'm working on, specified with IPPROTO_TCP flag) and, if I understood well, the char buffer[] contains only the payload, useless to me.
So, if I'm working on a too high level, I should go lower: once I saw a simple raw socket sniffer where an unsigned char buffer[65535] was cast to struct ethhdr, iphdt, tcphdr and it could see all the flags of all the headers, all the stats I'm interested in!
After the joy, the disappointment: since raw sockets work on a low level they don't have some concepts vital to my proxy; raw sockets can't bind, listen and accept; my proxy is listening on a fixed port, but raw sockets don't know what a port is, it belongs to the TCP level and they bind to a specified interface with setsockopt.
So, if I'd socket(PF_INET, SOCK_RAW, ntohs(ETH_P_ALL)) I should be able to parse the buffer where I recv() and send() at .7 and .8, but I should use recvfrom() and sendto()...but all this sounds quite messy, and it envolves a nice refactoring of my code.
How can I keep intact the structure of my proxy (bind, listen, accept to a fixed port and interface) and increase my line of vision for IP and TCP headers?
My suggestion is to open a raw socket in, for example, another thread of your application. Sniff all traffic and filter out the relevant packets by addresses and port numbers. Basically you want to implement your own packet sniffer:
int sniff()
{
int sockfd;
int len;
int saddr_size;
struct sockaddr saddr;
unsigned char buffer[65536];
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if (sockfd < 0) {
perror("socket");
return -1;
}
while (1) {
saddr_size = sizeof(saddr);
len = recvfrom(sockfd, buffer, sizeof(buffer), 0, &saddr, &saddr_size);
if (len < 0) {
perror("recvfrom");
close(sockfd);
return -1;
}
// ... do the things you want to do with the packet received here ...
}
close(sockfd);
return 0;
}
You can also bind that raw socket to a specific interface if you know which interface is going to be used for the proxy's traffic. For example, to bind to "eth0":
setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 4);
Use getpeername() and getsockname() function calls to find the local and remote addresses and port numbers of your TCP connections. You'll want to filter the packets by those.
I am trying to send an OAM ethernet frame using raw socket. I was successful in doing so.
The send function I have written is:
int send_frame(sock_info *info,char *buf,int length)
{
struct sockaddr_ll dest_addr;
memset(&dest_addr,0,sizeof(struct sockaddr_ll));
dest_addr.sll_family = PF_PACKET;
dest_addr.sll_protocol = htons(8902);
dest_addr.sll_ifindex = info->if_index;
dest_addr.sll_halen = ETH_MAC_ADDR_LEN;
dest_addr.sll_pkttype = PACKET_OTHERHOST;
dest_addr.sll_hatype = ARPHRD_ETHER;
memset(dest_addr.sll_addr,0,8);
dest_addr.sll_addr[0] = 0x00;
dest_addr.sll_addr[1] = 0xE0;
dest_addr.sll_addr[2] = 0x0C;
dest_addr.sll_addr[3] = 0x00;
dest_addr.sll_addr[4] = 0x95;
dest_addr.sll_addr[5] = 0x02;
return sendto(info->sock_fd, buf, length, 0, (struct sockaddr*) &dest_addr, sizeof(struct sockaddr_ll));
}
I was unable to capture the packet using wireshark. After tryiing too many things, I found out that buffer used to send should have all ethernet frame fields (starting from destination address). When I added the destination and source address and other ethernet fields into the buffer, I was able to capture the packet using wireshark. So the send function doesn't use the MAC address stored in dest_addr.sll_addr.
My question is, Then what's the need of sll_addr field in the struct sockaddr_ll? Manuals say that it is the destination MAC address.
To me it sounds like it works as the manual page describes it (man 7 packet):
SOCK_RAW packets are passed to and from the device driver without any
changes in the packet data. When receiving a packet, the address is
still parsed and passed in a standard sockaddr_ll address structure.
When transmitting a packet, the user supplied buffer should contain the
physical layer header. That packet is then queued unmodified to the
network driver of the interface defined by the destination address.
Some device drivers always add other headers. SOCK_RAW is similar to
but not compatible with the obsolete PF_INET/SOCK_PACKET of Linux 2.0.
The buffer here refers to the 2nd parameter of sendto(). So, the stuct sockaddr_ll is only used to return data to the caller, not to format the RAW packet. Maybe you want to user SOCK_DGRAM or libpcap instead?
I'm working with Cortex M3, Stellaris® LM3S6965 Evaluation Board. I'm sending an UDP packet to my pc. That works because I checked it with wireshark. But what I do see is that I don't have a source port. And I have no clue how so solve this.
I call this function to sent the a udp packet
void send_udp(){
RIT128x96x4Enable(1000000);
RIT128x96x4StringDraw("UDP data verzonden..", 0, 40, 15);
struct ip_addr serverIp;
IP4_ADDR(&serverIp,192,168,1,100);
u16_t port;
port = 64000;
struct udp_pcb * pcb;
pcb = udp_new();
udp_bind(pcb, &serverIp, port);
udp_recv(pcb, udp_echo_recv, NULL);
struct pbuf *p;
char msg[]="request";
//Allocate packet buffer
p = pbuf_alloc(PBUF_TRANSPORT,sizeof(msg),PBUF_RAM);
memcpy (p->payload, msg, sizeof(msg));
udp_sendto(pcb, p, &serverIp, port);
pbuf_free(p); //De-allocate packet buffer
}
Wireshark example of packet: (click here to enlarge)
The call to udp_bind() should assign the local port, but it seems to be failing for you.
The number you're using (64000) is in the range called dynamic, private or ephemeral ports, which might be why it's not working as expected.
From the documentation, udp_bind() supports port number 0 to get a dynamically assigned number; this is typically the way to go if the source port isn't important.
I also saw that "time to live" in the ipv4 pcb was 0.
So I added this line,
pcb->ttl = UDP_TTL; // Time to live
This solved my issue
What I wanna do: Implement a layer 2 protocol in user-space.
So I'm using pcap under Linux 2.6.32 to sniff packets:
...
struct pcap_t *pcap_h = pcap_open_live("wlan0", BUFSIZ, 1, 0, errbuf);
...
while (1) {
int ret = pcap_loop(pcap_h, -1, newpkt_callback, NULL);
...
}
...
Which works just fine for all packets. But, when I use pcap to send packets with no ether_head and no IP header:
const char pkt[] = "WHATEVER";
nsent = pcap_sendpacket(pcap_h, (const u_char *)pkt, len);
...
I can only sniff the packet on the localhost, and not on other laptops that are running the same program. So the question is "how can I broadcast messages without ether_head on a wlan"? Any pointers would be appreciated.
You can't do this if you are using an access point (infrastructure mode), as the access point relays the frames between other wireless stations and thus must know how to talk your layer 2 protocol.
I suggest implementing your protocol at layer 3 (and you may want to look into PF_PACKET sockets).
You have to send complete frame with it's headers, not just some random data.
Take a look at this manual http://linux.die.net/man/3/pcap at function pcap_inject(). In creating new frame this could help http://www.tcpdump.org/pcap.html, or just use libnet library http://libnet.sourceforge.net/libnet.html.