I am trying to work with pcap but I have some troubles reading a sequence number.
I use the code below to listen for an incomming packet, but when I try to read the sequence number the program halts without an error. Just stops the execution silently.
This code largely comes from the pcap tutorial from the tcpdump site.
bpf_u_int32 net=0, mask=0;
pcap_t *descr = NULL;
struct bpf_program filter;
struct ip *iphdr = NULL;
struct tcphdr *tcphdr = NULL;
struct pcap_pkthdr pkthdr;
const unsigned char *packet = NULL;
char pcap_errbuf[PCAP_ERRBUF_SIZE];
char filter_exp[] = "tcp port 111 dst host 10.0.0.10";
char * dev;
// Define the device
dev = pcap_lookupdev(pcap_errbuf);
if (dev == NULL) {
printf( "Couldn't find default device: %s\n", pcap_errbuf); fflush(stdout);
exit(1);
}
// Find the properties for the device
if( pcap_lookupnet(dev, &net, &mask, pcap_errbuf) == -1 ){
printf("Couldn't get netmask for device %s: %s\n", dev, pcap_errbuf); fflush(stdout);
net = 0;
mask = 0;
}
// Open the session in non-promiscuous mode
descr = pcap_open_live(dev, BUFSIZ, 0, 1000, pcap_errbuf);
if (descr == NULL) {
printf("Couldn't open device %s: %s\n", dev, pcap_errbuf); fflush(stdout);
exit(1);
}
// Compile and apply the filter
if( pcap_compile(descr, &filter, filter_exp, 0, net) == -1) {
printf("Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(descr)); fflush(stdout);
exit(1);
}
if (pcap_setfilter(descr, &filter) == -1) {
printf( "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(descr)); fflush(stdout);
exit(1);
}
packet = pcap_next(descr, &pkthdr );
iphdr = (struct ip *)(packet+14);
tcphdr = (struct tcphdr *)(packet+14+20);
printf("test1\n"); fflush( stdout );
printf("SEQ: %d\n", ntohl(tcphdr->th_seq) ); fflush( stdout );
printf("test2\n");
pcap_close(descr);
The "test1" is printed, but the "test2" and the "SEQ: %d" isn't. Its hard to debug if there's no error at all.
Anyone seen this before?
Thanks
Nikolai Fetissov is correct - you must check whether pcap_next() returns NULL or not. It might return NULL if, for example, the timeout expires and no packets have arrived. In that case, you should keep looping until it returns a non-null value.
However, it could also return NULL if there's an error, and that error might mean that you won't get any more packets. A better routine to use is pcap_next_ex(), which returns returns 1 if the packet was read without problems, 0 if packets are being read from a live capture and the timeout expired, -1 if an error occurred while reading the packet, and -2 if packets are being read from a savefile and there are no more packets to read from the savefile.
In your case, you're doing a live capture, so you should use pcap_next_ex(), and loop until it returns either 1, in which case you print the packet information, or -1, in which case you report an error and exit:
int status;
while ((status = pcap_next_ex(descr, &pkthdr, &packet)) == 0)
;
if (status == -1) {
fprintf(stderr, "pcap_next_ex failed: %s\n", pcap_geterr(descr));
exit(1);
}
iphdr = (struct ip *)(packet+14);
tcphdr = (struct tcphdr *)(packet+14+20);
printf("test1\n"); fflush( stdout );
printf("SEQ: %d\n", ntohl(tcphdr->th_seq) ); fflush( stdout );
printf("test2\n");
pcap_close(descr);
Note also that there's no guarantee that the IPv4 header is 20 bytes long - it could be longer, so you need to extract the header length from the first byte of the IPv4 header (the header length/version field), multiply it by 4 (as it's in units of 4-byte words), and use that when calculating the address of the TCP header, rather than using a hard-coded 20.
In addition, you should also make sure that the link-layer header type of the device, as returned by pcap_datalink(descr), is DLT_EN10MB, to make sure the packets have Ethernet headers rather than some other type of header.
In addition, I just copied your printf code, as I was concentrating on the capture problem. Somebody else added an ntohl() call, which is necessary when printing the sequence number - multi-byte numerical fields in IP and TCP headers are in "network byte order", i.e. big-endian, but you might be running on a little-endian machine, so the sequence number has to be converted to the host byte order before printing it.
Related
I am learning to write pcap code in c. Below i have written a simple c code to automatically detect a device for snifiing, getting ip and subnet mask, getting link layer headers and filtering traffic and then printing packet size.
Code complies successfully but gets stuck at
Network device found: wlo1
when run. Removing the filter part does print the packet size. And removing the priting packet part; the program complies and runs successfully.
I think i am lacking understanding of filtering part.
I compile using(on linux): gcc program_name -lpcap
Output of the code is:
Network device found: wlo1
wlo1 is wlan device
#include <stdio.h>
#include <pcap.h>
int main(int argc, char *argv[]){
char *dev; //device automatically detected for sniffing
char errbuf[PCAP_ERRBUF_SIZE]; //error string
pcap_t *handle; //session hnadle
struct bpf_program fp; //The compiled filter expression
char filter_exp[] = "port 23"; //The filter expression
bpf_u_int32 mask; //The netmask of our sniffing device
bpf_u_int32 net; //The IP of our sniffing device
struct pcap_pkthdr header;
const unsigned char *packet;
//device detection block
dev = pcap_lookupdev(errbuf);
if (dev == NULL){
printf("Error finding device: %s\n", errbuf);
return 1;
}
printf("Network device found: %s\n", dev);
//opening device for sniffing
handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
if(handle == NULL){
fprintf(stderr,"Couldn't open device %s : %s\n",dev,errbuf);
return 1;
}
// //check for link-layer header of the device
if(pcap_datalink(handle) != DLT_EN10MB){ //for ethernet data link layer
if(pcap_datalink(handle) != DLT_IEEE802_11){ //for wlan data link layer
fprintf(stderr, "Device %s doesn't provide WLAN headers - not supported\n", dev);
return 1;
}
else{
fprintf(stderr, "Device %s doesn't provide Ethernet headers - not supported\n", dev);
return 1;
}
}
//block to get device ip and subnet mask
if(pcap_lookupnet(dev, &net, &mask, errbuf) == -1){
fprintf(stderr, "Can't get netmask for device %s\n", dev);
net = 0;
mask = 0;
}
//block for filtering traffic we want to sniff
if(pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
return 1;
}
if(pcap_setfilter(handle, &fp) == -1) {
fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
return 1;
}
/* Grab a packet */
packet = pcap_next(handle, &header);
/* Print its length */
printf("Jacked a packet with length of [%d]\n", header.len);
/* And close the session */
pcap_close(handle);
return 0;
}
If wlo1 is capturing in monitor mode on a "protected" network (a network with traffic encrypted at the link layer, using WEP or WPA/WPA2/WPA3), then any filter that works above the link layer - such as a TCP/UDP-layer filter, which "port 80" is - will not work, because the packets, as delivered to the filtering code, will have the 802.11 payload encrypted, so filters won't work on them.
Therefore, no packets will pass the filter.
So, we have a long standing commercial product, that is well established and I've never seen this type of issue before. We use a client program to send data to a server. Sometimes, because of firewalls in customer environments, we allow the end user to specify outbound port ranges to bind, however, in this particular issue i'm seeing, we're not doing that, and are using port 0 to perform a bind. From everything i've read, this means to pick a random port. But what I can't find out is, what does that mean to the kernel/OS. If i'm asking for a random port, how can that already be in use?
Strictly speaking, only the unique pairing of src ip/src port & dst ip/port make the connection unique. I believe the same port can be used, if talking to another destination ip, but maybe that's not relevant here.
Also, this doesn't happen on all the customer's systems, only some. So, this may be some form of load related issue. The systems are fairly busy i'm told.
Here is the code we're using. I left out some of the ifdef code for windows, and left out what we do after the bind for shortness.
_SocketCreateClient(Socket_pwtP sock, SocketInfoP sInfo )
{
int nRetries; /* number of times to try connect() */
unsigned short port;
BOOL success = FALSE;
BOOL gotaddr = FALSE;
char buf[INET6_ADDRSTRLEN] ="";
int connectsuccess =1;
int ipv6compat =0;
#ifdef SOCKET_SEND_TIMEOUT
struct timeval time;
#endif /* SOCKET_SEND_TIMEOUT */
nRetries = sInfo->si_nRetries;
sock->s_hostName = strdup(sInfo->si_hostName);
#ifdef DEBUG_SOCKET
LogWrite(LogF,LOG_WARNING,"Socket create client");
LogWrite(LogF,LOG_WARNING,"Number of retries = %d", nRetries);
#endif
ipv6compat = GetIPVer();
if (ipv6compat == -1) /* ipv6 not supported */
gotaddr = GetINAddr(sInfo->si_hostName, &sock->s_sAddr.sin_addr);
else
gotaddr = GetINAddr6(sInfo->si_hostName, &sock->s_sAddr6.sin6_addr);
/* translate supplied host name to an internet address */
if (!gotaddr) {
/* print this message only once */
if ( sInfo->si_logInfo && ( sInfo->si_nRetries == 1 ) )
{
LogWrite(LogF, LOG_ERR,
"unable to resolve ip address for host '%s'", sInfo->si_hostName);
}
sock = _SocketDestroy(sock);
}
else {
if (ipv6compat == 1) /* ipv6 supported */
{
/* try to print the address in sock->s_sAddr6.sin6_addr to make sure it's good. from call above */
LogWrite(LogF, LOG_DEBUG2, "Before call to inet_ntop");
inet_ntop(AF_INET6, &sock->s_sAddr6.sin6_addr, buf, sizeof(buf));
LogWrite (LogF, LOG_DEBUG2, "Value of sock->s_sAddr6.sin6_addr from GetINAddr6: %s", buf);
LogWrite (LogF, LOG_DEBUG2, "Value of sock->s_sAddr6.sin6_scope_id from if_nametoindex: %d", sock->s_sAddr6.sin6_scope_id);
LogWrite (LogF, LOG_DEBUG2, "Value of sock->s_type: %d", sock->s_type);
}
/* try to create the socket nRetries times */
while (sock && sock->s_id == INVALID_SOCKET) {
int socketsuccess = FALSE;
/* create the actual socket */
if (ipv6compat == -1) /* ipv6 not supported */
socketsuccess = sock->s_id = socket(AF_INET, sock->s_type, 0);
else
socketsuccess = sock->s_id = socket(AF_INET6, sock->s_type, 0);
if ((socketsuccess) == INVALID_SOCKET) {
GETLASTERROR;
LogWrite(LogF, LOG_ERR, "unable to create socket: Error %d: %s", errno,
strerror(errno) );
sock = _SocketDestroy(sock);
}
else
{
/* cycle through outbound port range for firewall support */
port = sInfo->si_startPortRange;
while ( !success && port <= sInfo->si_endPortRange ) {
int bindsuccess = 1;
/* bind to outbound port number */
if ( ipv6compat == -1) /* ipv6 not supported */
{
sock->s_sourceAddr.sin_port = htons(port);
bindsuccess = bind(sock->s_id, (struct sockaddr *) &sock->s_sourceAddr,
sizeof(sock->s_sourceAddr));
}
else {
sock->s_sourceAddr6.sin6_port = htons(port);
inet_ntop(AF_INET6, &sock->s_sourceAddr6.sin6_addr, buf, sizeof(buf));
LogWrite(LogF, LOG_DEBUG,
"attempting bind to s_sourceAddr6 %s ", buf);
bindsuccess = bind(sock->s_id, (struct sockaddr *) &sock->s_sourceAddr6,
sizeof(sock->s_sourceAddr6));
}
if (bindsuccess == -1) {
GETLASTERROR;
LogWrite(LogF, LOG_ERR,
"unable to bind port %d to socket: Error %d: %s. Will attempt next port if protomgr port rules configured(EAV_PORTS).", port, errno, strerror(errno) );
/* if port in use, try next port number */
port++;
}
else {
/* only log if outbound port was specified */
if (port != 0)
{
if ( sInfo->si_sourcehostName ) {
LogWrite(LogF, LOG_DEBUG,
"bound outbound address %s:%d to socket",
sInfo->si_sourcehostName, port);
}
else {
LogWrite(LogF, LOG_DEBUG,
"bound outbound port %d to socket", port);
}
}
success = TRUE;
}
}
}
}
}
return(sock);
}
The errors we're seeing in our log file look like this. It's making 2 tries and both fail:
protomgr[628453] : ERROR: unable to bind port 0 to socket: Error 98: Address already in use. Will attempt next port if protomgr port rules configured(EAV_PORTS).
protomgr[628453] : ERROR: unable to bind port(s) to socket: Error 98: Address already in use. Consider increase the number of EAV_PORTS if this msg is from protomgr.
protomgr[628453] : ERROR: unable to bind port 0 to socket: Error 98: Address already in use. Will attempt next port if protomgr port rules configured(EAV_PORTS).
protomgr[628453] : ERROR: unable to bind port(s) to socket: Error 98: Address already in use. Consider increase the number of EAV_PORTS if this msg is from protomgr.
So, it looks like this was related to the system running out of available ports, and it being configured to only have about 9000 port available.
This setting, in /etc/sysctl.conf controls the available ports:
net.ipv4.ip_local_port_range = 9000 65500
the first number is the starting port, and the second is the max. This example was pulled from a unaltered Suse Enterprise linux server 11.0.
The customer of ours who reported this problem had their configured in such a way it only had around 9000 ports available in the range they defined, and all were used on the system.
Hopefully, this helps someone else in the future.
I work under multi platform hw timestamp application. I am little bit confused in linux timestamp behaviour. I got error 'No message of desired type' from recvmsg and try handle it like error. My debug code below. As I see expected behavior:
Sent time stamps the outgoing packet is looped back to
the socket's error queue with the send time stamp attached.
Clone of sent packet can be received with recvmsg with flags |= MSG_ERRQUEUE.
recvmsg return outgoing packet with sock_extended_err (ee_errno==ENOMSG). ENOMSG is 'No message of desired type'.
So it look like linux should keep clone of outgoing packet in error queue for feature time calculation.
Should I skip ENOMSG in my error handler code?
if (errno == EAGAIN || errno == EINTR || errno == ENOMSG)
break;
Why it reported via error message? Probably it is not clear why ENOMSG expected or not?
I got: error description = 'No message of desired type' from recvmsg.
recvmsg(sock, &msg, recvmsg_flags|MSG_ERRQUEUE);
for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg))
{
...
switch (cmsg->cmsg_level) {
case SOL_IP:
...
pkt.cmsg = (const struct cmsghdr*)cmsg;
pkt.msg = (const struct msghdr*)msg;
print_sol_ip(&pkt);
break;
}
}
/* Network level L3.
* Note that there is no TCP error queue;
* MSG_ERRQUEUE flag can not be used for socket type SOCK_STREAM.
* Thus, any errors can only be obtained as the value returned by the socket,
* or through option SO_ERROR.
*/
static void print_sol_ip(struct cmh_packet *pkt)
{
const int type = pkt->cmsg->cmsg_type;
const struct cmsghdr *cmsg = pkt->cmsg;
if (pkt->cmsg->cmsg_level != SOL_IP) {
printf("Wrong handler.\n");
return;
}
printf("SOL::IP::");
switch (type) {
case IP_RECVERR:
printf("RECVERR::\n");
struct sock_extended_err *err;
struct sockaddr *sk_addr;
struct sockaddr_in *sk_addrin;
socklen_t sk_addrlen;
err = (struct sock_extended_err *)CMSG_DATA(pkt->cmsg);
if ((sk_addr = malloc(sizeof(struct sockaddr))) == NULL) return;
/*
* The original destination address of the datagram that caused the error is supplied via msg_name
* For local errors, no address is passed (this can be checked with the cmsg_len member of the cmsghdr).
*/
printf("pointer to the data: %p\n", pkt->cmsg->__cmsg_data);
printf("data byte count, including header: %zd\n", pkt->cmsg->cmsg_len); /* CMSG_LEN */
printf("originating protocol: %d\n", pkt->cmsg->cmsg_level); /* SOL_SOCKET */
printf("protocol-specific type: %d\n", pkt->cmsg->cmsg_type); /* SCM_RIGHTS */
printf("%s = %d \n", "error number", err->ee_errno);
printf("%s = %d \n", "error origin", err->ee_origin); /* origin: SO_EE_ORIGIN_ICMP..LOCAL..NONE */
printf("%s = %d \n", "error type", err->ee_type); /* type: ICMP_NET_UNREACH..ICMP_HOST_UNREACH */
printf("%s = %d \n", "error code", err->ee_code);
printf("%s = %d \n", "error pad", err->ee_pad);
printf("%s = %d \n", "error info", err->ee_info);
printf("%s = %d \n", "error data", err->ee_data);
printf("error description = '%s'\n", strerror(err->ee_errno));
sk_addr = (struct sockaddr*)pkt->msg->msg_name;
sk_addrlen = pkt->msg->msg_namelen;
sk_addrin = (struct sockaddr_in*)sk_addr;
printf("%s:%d addrlen: %d\n", inet_ntoa(sk_addrin->sin_addr), ntohs(sk_addrin->sin_port), sk_addrlen);
print_af(sk_addr->sa_family);
break;
case IP_PKTINFO:
printf("PKTINFO::\n");
struct in_pktinfo *pki;
pki = (struct in_pktinfo *)CMSG_DATA(pkt->cmsg);
printf("Source interface index %u local address %s destination address %s",
pki->ipi_ifindex,
inet_ntoa(pki->ipi_spec_dst),
inet_ntoa(pki->ipi_addr));
break;
case IP_RECVOPTS: /* Routing header and other options are already installed on the local host. */
printf("IP_RECVOPTS::\n");
break;
case IP_RETOPTS:
printf("IP_RETOPTS::\n");
break;
case IP_TOS: /* the field is used to create network packet priorities.
There are several default values flag TOS: IPTOS_LOWDELAY,
in order to minimize delays for the traffic, IPTOS_THROUGHPUT,
to improve throughput, IPTOS_RELIABILITY, to increase
reliability, IPTOS_MINCOST, should be used for "optional data"
that can be sent at the minimum speed. */
printf("IP_TOS::\n");
break;
case IP_TTL: /* ip_default_ttl */
printf("IP_TTL::\n");
int ttl;
int *pttl;
pttl = (int *) CMSG_DATA(pkt->cmsg);
ttl = *pttl;
printf("ttl value = %d\n", ttl);
break;
case IP_HDRINCL: /* Enabling this flag means that the user has already added the IP header to the top of their data. */
printf("IP_HDRINCL::\n");
break;
case IP_MTU:
printf("IP_MTU::\n");
//TODO: getsockopt(sock, level, IP_MTU, IP_MTU_value_get, size);
break;
case IP_ROUTER_ALERT: /* It transmits this socket all packets that are sent with the option
* of IP Router Alert. This option is used only in the
* type of sockets RAW.
* */
printf("IP_ROUTER_ALERT::\n");
break;
case IP_MULTICAST_TTL:
printf("IP_MULTICAST_TTL::\n");
break;
default:
printf("TYPE %d\n", cmsg->cmsg_type);
break;
}
}
It was clear that I got ENOMSG from loopback timestamped skb. Like described in linux/Documentation/networking/timestamping.txt. And finally I found that ip_recv_error() extract skb from sk->sk_error_queue (errqueue) and reset error sk->sk_err = 0. But it also check if exist additional skb's in sk_error_queue. My errqueue had several skb in sk_error_queue that is why ip_recv_error in the end check errqueue found that it had skb's.
skb2 = skb_peek(&sk->sk_error_queue);
it had skb2 and sk->sk_err was reset back to ENOMSG.
sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
skb2 previously came from
void skb_tstamp_tx(struct sk_buff *orig_skb,
struct skb_shared_hwtstamps *hwtstamps)
serr = SKB_EXT_ERR(skb);
serr->ee.ee_errno = ENOMSG;
No matter from which queue you will read if errqueue contain skb (skb cb control buffer should contain error in ee_errno) recvmsg will report error. Because udp_recvmsg call __skb_recv_datagram
and it check if struct sk containe error.
int error = sock_error(sk);
If so it will report -1 with error that was found in skb. So it is critical for udp to read all messages from sk_error_queue. Because during last read sk->sk_err will reset (or getsockopt(SO_ERROR)). Or just make skip and it will read next time with some delay.
i have made a packet sniffer using libpcap on C++.
I am using pcap_loop and calling a loopback function , which at the moment i havent put much thought of.
Here is my code.
int PacketSniff(int *count)
{
int ifnum;
int NumOfDevs=0;
char errbuf[PCAP_ERRBUF_SIZE];
bpf_u_int32 ip;
bpf_u_int32 netmask;
struct in_addr ip_addr , netmask_addr;
pcap_if_t *devs , *d;
pcap_t *handler;
char packet_filter[] = "ip";
struct bpf_program fcode;
/* Find all interface devices */
pcap_findalldevs(&devs, errbuf);
for(d=devs; d; d=d->next)
{
printf("%d. %s", ++NumOfDevs, d->name);
if (d->description)
{
printf(" (%s)\n", d->description);
}
else
{
printf(" (No description available)\n");
}
}
if(NumOfDevs==0)
{
printf("\nNo interfaces found!\n");
return (-1);
}
/* Prompt User to select interface */
printf("Enter the interface number (1-%d):\n",NumOfDevs);
scanf("%d",&ifnum);
if(ifnum < 1 || ifnum > NumOfDevs)
{
printf("\nInterface number out of range.\n");
/* Free the device list */
pcap_freealldevs(devs);
return (-1);
}
/* Jump to the selected adapter/interface */
for(d=devs; ifnum>1 ;d=d->next, ifnum--);
/* Open the selected adapter/interface */
handler = pcap_open_live(d->name, 65535, 0, 2000, errbuf);
if ((handler = pcap_open_live(d->name, 65535, 0, 2000, errbuf)) == NULL)
{
fprintf(stderr, "Couldn't open device %s: %s\n", d->name, errbuf);
return(-1);
}
if (pcap_datalink(handler) != DLT_EN10MB )
{
fprintf(stderr,"\nThis program works only on Ethernet networks.\n");
pcap_freealldevs(devs);
return -1;
}
/* This means that we set the datalink layer header size at 14 */
int linkhdrlen = 14;
if (pcap_lookupnet(d->name, &ip, &netmask, errbuf) <0 )
{
fprintf(stderr, "Can't get netmask for device %s\n", d->name);
netmask = 0;
ip = 0;
}
/* Compile the filter */
if (pcap_compile(handler, &fcode, packet_filter, 1, netmask) <0 )
{
fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax. Error: %s\n", errbuf);
pcap_freealldevs(devs);
return -1;
}
/* Set the filter */
if (pcap_setfilter(handler, &fcode)<0)
{
fprintf(stderr,"\nError setting the filter. Error: %s\n", errbuf);
pcap_freealldevs(devs);
return -1;
}
printf("\nListening for packets on interface <%s>...\n", d->name);
/* At this point, we don't need any more the device list. Free it */
pcap_freealldevs(devs);
pcap_loop(handler, 0, my_callback, NULL);}
And my_callback is like this:
void my_callback(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_ptr){
struct tm ltime;
char timestr[16];
struct ip_header *iphdr;
struct tcp_header *tcphdr;
time_t local_tv_sec;
/* Convert the timestamp to readable format */
local_tv_sec = header->ts.tv_sec;
localtime_r(&local_tv_sec , <ime);
strftime( timestr, sizeof timestr, "%H:%M:%S", <ime);
/* Print timestamp and length of the packet */
printf("Time >> %s.%.6d \nPacket Length:%d \n\n", timestr, header->ts.tv_usec, header->len);
/* Retireve the position of the ip header http://www.tcpdump.org/pcap.html */
iphdr = (ip_header *) (pkt_ptr +14);
// Advance to the transport layer header then parse and display
// the fields based on the type of hearder: tcp, udp or icmp.
pkt_ptr += 4*iphdr->ver_ihl ;
tcphdr = (tcp_header *)(pkt_ptr + 14);
/* print ip addresses and tcp ports */
printf("%d.%d.%d.%d : %d ---> %d.%d.%d.%d : %d\n\n",
iphdr->saddr.byte1,
iphdr->saddr.byte2,
iphdr->saddr.byte3,
iphdr->saddr.byte4,
tcphdr->src_port,
iphdr->daddr.byte1,
iphdr->daddr.byte2,
iphdr->daddr.byte3,
iphdr->daddr.byte4,
tcphdr->dst_port);}
Now i can sniff packets and print various things .
But my goal is to Extract Stats from the packets (like numOfpackets , numOfTCPpackets , numOfIncomingPAcket , numOfOutgoingPackets , Packet Size Variance , Time Interval Variance ) while they are being sniffed .
But i want this to be done in 1000ms Time-Windows.
For example: Every 1000ms i want an output file of..
numOfTCPPackets = ....
numof = ....
.
.
.
My questions are :
How can i incorporate those Time-Windows?
How to extract the needed stats without interfering too muchwith the sniffing speed.?
Thank you a lot!
Use pcap_next() instead of pcap_loop() to get the packet and set the timeout with pcap_set_timeout() to a small value such as 10 milliseconds to prevent pcap_next() blocking forever so that your code to write the statistics to the file gets a chance to run. You need to call pcap_next() in a loop and have code like the following after the pcap_next() call:
if (cur_time64() - last_time64 >= stat_time64)
{
last_time64 += stat_time64;
print_statistics_to_file();
}
...where cur_time64() returns the current time as a 64-bit integer in microseconds since the epoch (you can use gettimeofday() to implement cur_time64() if you use a Unix-like operating system). stat_time64 would be 1 second, i.e. 1000*1000, in your example.
Then, proceed to process the packet. Check the return value of pcap_next() to see if it returned a packet: if no, continue the loop; if yes, process the packet.
To do the checks without interfering too much with the sniffing speed, your only option is to write the code as efficiently as possible. Handle only those header fields you absolutely need to handle, i.e. you can avoid checking the checksums of IP and TCP headers.
This code sends and recv s txt file perfectly but cannot do it to otehr formats like .exe or .img. Please help me with these as I need to use htonl or htons??
Take a look!!
Here is the server side recv function ::
if (socket_type != SOCK_DGRAM)
{
fi = fopen (final,"wb");
retval = recv(msgsock, recv_buf, strlen(recv_buf), 0);
/*recv_buf[retval] = '\0';
fprintf (fi,"%s",recv_buf);*/
int i;
i=atoi(recv_buf);
char *q;
q=(char *)malloc(i*sizeof(char));
retval = recv(msgsock, q, strlen(q), 0);
//printf ("%s",q);
fwrite(q,i,1,fi);
fclose(fi);
}
else
{
retval = recvfrom(msgsock,recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&from, &fromlen);
printf("Server: Received datagram from %s\n", inet_ntoa(from.sin_addr));
printf ("SOCK_DGRAM");
}
if (retval == SOCKET_ERROR)
{
fprintf(stderr,"Server: recv() failed: error %d\n", WSAGetLastError());
closesocket(msgsock);
//continue;
}
else
printf("Server: recv() is OK.\n");
if (retval == 0)
{
printf("Server: Client closed connection.\n");
closesocket(msgsock);
//continue;
}
printf("Server: Received %d bytes, data from client\n", retval);
The client side sending function :::
void send_command()
{
int bytesent;
FILE *file_out;
//file_out = fopen(file_path,"rb");
char str_all[100000];//flag [30]="end";
///////////////////////getsize//////////////
char fsize[5];
int filesize;
file_out = fopen(file_path, "rb");
fseek(file_out, 0, SEEK_END);
filesize = ftell(file_out);
rewind (file_out);
itoa (filesize,fsize,10);
/////////////////////////////////////////////
send (ConnectSocket, fsize, strlen (fsize), 0);
char *r = (char *)malloc (filesize * sizeof(char));
fread(r,filesize,1,file_out);
bytesent = send( ConnectSocket, r, strlen(r), 0 );
printf("\nClient: Bytes sent: %ld\n", bytesent);
fclose (file_out);
/*while (fscanf(file_out,"%s",&str_all) != EOF)
{
bytesent = send( ConnectSocket, str_all, strlen(str_all), 0 );
printf("\nClient: Bytes sent: %ld\n", bytesent);
//Sleep(500);
}*/
/*printf("%s",flag);
send( ConnectSocket, flag, strlen(flag), 0 );*/
WSACleanup();
//return 0;
}
OK, there are multiple issues with your program.
You are transferring binary data. The receiver is only going to see a sequence of bytes. There is no way for the receiver to know the end of the data, since all possible values of char are legal data values. If you were sending text data, you could say that a 0 signifies the end of the data, but now you can't. So, you have to decide on a "protocol" between the server and the client—the simplest is that the server sends the length of the data in the first 4 bytes (read up on ntonl() and ntohl() for how to do this portably). Then, the receiver will know exactly how many bytes to read.
You declare the receiver buffer as char *recv_buf, and similarly for recv_buf1. You don't allocate any storage for any of the two pointers, so they aren't pointing to anywhere useful. Then, your recv call is: recv(msgsock, recv_buf, sizeof(recv_buf), 0); This also has problems. The first is the one mentioned above: you don't have storage for recv_buf. The second is that after you do allocate storage for recv_buf, you are taking the size of a char pointer instead of the length of the buffer recv points to. One easy way to solve both the issues would be to declare recv_buf as: char recv_buf[SIZE]; and then use sizeof recv_buf in the recv() call.
I haven't looked at the rest of your code. You probably need a good C and network programming introduction.
I think you're confusing the null-termination of a C string with the end of a packet sent on a socket. There is no "termination" of a packet, it's just a string of bytes. Zeros are completely legal, and you pass (and receive) the length explicitly. You certainly don't need to use the out-of-band facilities to receive multiple packets. Can you be more specific about what you're asking?