libpcap and wireless signal capture - c++

I am trying to write a c++ app (linux) that would capture a wireless packet along with the associated Signal strength (in dBm). The capturing part is easy but the problem is I can't find any documentation on how to get the signal strength for each packet.
Is it part of the header?
Here's what I have so far:
printf("Device: %s\n", dev);
printf("Number of packets: %d\n", num_packets);
printf("Filter expression: %s\n", filter_exp);
/* open capture device */
pcap_t *handler = pcap_create("wlan0", errbuf);
if (handler == NULL)
{
exit(-1);
}
if(pcap_set_rfmon(handler,1)==0 )
{
printf("monitor mode enabled\n");
}
pcap_set_snaplen(handler, 2048); // Set the snapshot length to 2048
pcap_set_promisc(handler, 0); // Turn promiscuous mode off
pcap_set_timeout(handler, 512); // Set the timeout to 512 milliseconds
int status = pcap_activate(handler);
/* now we can set our callback function */
pcap_loop(handle, num_packets, got_packet, NULL);
Here is the got_packet code:
/* define ethernet header */
ethernet = (struct sniff_ethernet*)(packet);
/* define/compute ip header offset */
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
size_ip = IP_HL(ip)*4;
if (size_ip < 20) {
printf(" * Invalid IP header length: %u bytes\n", size_ip);
return;
}
/* print source and destination IP addresses */
printf(" From: %s\n", inet_ntoa(ip->ip_src));
printf(" To: %s\n", inet_ntoa(ip->ip_dst));
/* determine protocol */
switch(ip->ip_p) {
case IPPROTO_TCP:
printf(" Protocol: TCP\n");
break;
case IPPROTO_UDP:
printf(" Protocol: UDP\n");
return;
case IPPROTO_ICMP:
printf(" Protocol: ICMP\n");
return;
case IPPROTO_IP:
printf(" Protocol: IP\n");
return;
default:
printf(" Protocol: unknown\n");
return;
}
/* define/compute tcp header offset */
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
size_tcp = TH_OFF(tcp)*4;
if (size_tcp < 20) {
printf(" * Invalid TCP header length: %u bytes\n", size_tcp);
return;
}
printf(" Src port: %d\n", ntohs(tcp->th_sport));
printf(" Dst port: %d\n", ntohs(tcp->th_dport));
/* define/compute tcp payload (segment) offset */
payload = (char *)(packet + SIZE_ETHERNET + size_ip + size_tcp);
/* compute tcp payload (segment) size */
size_payload = ntohs(ip->ip_len) - (size_ip + size_tcp);
/*
* Print payload data; it might be binary, so don't just
* treat it as a string.
*/
if (size_payload > 0) {
printf(" Payload (%d bytes):\n", size_payload);
//print_payload(payload, size_payload);
}
Any help would be much appreciate it.
UPDATE:
/***************/
Here's an update:
So based on my research and as Guy Scott mentioned I was looking for a wrong info. I need to look at wireless packets and was instead loading ethernet packet. So here's the updated code:
pcap_set_snaplen(handle, 2048); // Set the snapshot length to 2048
pcap_set_promisc(handle, 1); // Turn promiscuous mode off
pcap_set_timeout(handle, 512); // Set the timeout to 512 milliseconds
int status = pcap_activate(handle);
if(pcap_set_datalink(handle, DLT_IEEE802_11_RADIO) == -1) {
printf("Couldn't set datalink type %s: %s\n", device, pcap_geterr(handle));
}
So the problem now is parsing the packet which seems to be a pretty hard issue. I am interested in the source address, destination address and the associated signal etc. I don't know how to match and load the data from the packet and match it to the radiotap struct.
struct ieee80211_radiotap_header {
u_int8_t it_version; /* set to 0 */
u_int8_t it_pad;
u_int16_t it_len; /* entire length */
u_int32_t it_present; /* fields present */
} __attribute__((__packed__));
/* Presence bits */
#define RADIOTAP_TSFT 0
#define RADIOTAP_FLAGS 1
#define RADIOTAP_RATE 2
#define RADIOTAP_CHANNEL 3
#define RADIOTAP_FHSS 4
#define RADIOTAP_ANTENNA_SIGNAL 5
#define RADIOTAP_ANTENNA_NOISE 6
#define RADIOTAP_LOCK_QUALITY 7
#define RADIOTAP_TX_ATTENUATION 8
#define RADIOTAP_DB_TX_ATTENUATION 9
#define RADIOTAP_DBM_TX_POWER 10
#define RADIOTAP_ANTENNA 11
#define RADIOTAP_DB_ANTENNA_SIGNAL 12
void process_packet (u_char * args, const struct pcap_pkthdr *header, const u_char * packet)
{
struct ieee80211_radiotap_header *packet_header = (struct ieee80211_radiotap_header *) header;
// This is where I am stuck
Can someone tell me once I've captured the packet, how do I pull out the above values from it?
Thanks

Every program that calls pcap_open_live(), pcap_create()/pcap_activate(), or pcap_open_offline() should, if the calls succeed, call pcap_datalink() to find out what the link-layer header type of the capture is.
There are no exceptions to this rule.
Then see the link-layer header types page for tcpdump.org to see what the values returned by pcap_datalink() mean. Compare them against the DLT_ values listed there. The ones you're likely to get are DLT_IEEE802_11, which has no signal-strength information, and DLT_PRISM_HEADER, DLT_IEEE802_11_RADIO, and DLT_IEEE802_11_RADIO_AVS, which do have signal strength information. See the links for the latter three possibilities for information on how the signal strength information (and other radio metadata) is represented in the packet data.
(And, yes, that's three options for radio metadata, so the link given in another answer is to an incomplete source; most of the time you will probably get radiotap headers, not AVS or Prism headers. Radiotap is more general, as it's designed to be extensible, but it's more complicated to parse.)

I was stumbling upon the same problem, thought I should share my solution.
The signal strength is not in the header of PCAP callback, but within the packet. For DLT_IEEE802_11_RADIO the signal and noise could be:
void process_packet (u_char * args,
const struct pcap_pkthdr *header,
const u_char * packet){
int8_t signal_dbm = packet[22];
int8_t noise_dbm = packet[23];
....
}
But I found 22 and 23 by looking into WireShark.
The nicer solution would be of course using the radiotap (GitHub).
Here is an example:
void process_packet (u_char * args,
const struct pcap_pkthdr *header,
const u_char * packet) {
struct ieee80211_radiotap_iterator iterator;
int ret = ieee80211_radiotap_iterator_init(&iterator, packet, header->len, NULL);
while (!ret) {
ret = ieee80211_radiotap_iterator_next(&iterator);
if (ret) break;
switch (iterator.this_arg_index) {
case IEEE80211_RADIOTAP_TSFT:
printf("timestamp: %lu\n", (uint64_t)*iterator.this_arg);
break;
case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
printf("sig: %d\n", (int8_t)*iterator.this_arg);
break;
case IEEE80211_RADIOTAP_DBM_ANTNOISE:
printf("noise: %d\n", (int8_t)*iterator.this_arg);
break;
default:
break;
}
}
}

Related

SIM 808 TCP connection (Arduino library)

I AM WORKING WITH SIM808 for tcp connection, below is what my code looks like it is pretty much the basic tcp connection and i keep get fetch over and I can tell that is a problem with my content lenght but i feel if i have a better understanding that will be fine.
#include <DFRobot_sim808.h>
#include <SoftwareSerial.h>
//#define PIN_TX 10
//#define PIN_RX 11
//SoftwareSerial mySerial(PIN_TX,PIN_RX);
//DFRobot_SIM808 sim808(&mySerial);//Connect RX,TX,PWR,
DFRobot_SIM808 sim808(&Serial);
char http_cmd[] = "GET /media/uploads/mbed_official/hello.txt HTTP/1.0\r\n\r\n";
char buffer[512];
void setup(){
//mySerial.begin(9600);
Serial.begin(9600);
//******** Initialize sim808 module *************
while(!sim808.init()) {
delay(1000);
Serial.print("Sim808 init error\r\n");
}
delay(3000);
//*********** Attempt DHCP *******************
while(!sim808.join(F("cmnet"))) {
Serial.println("Sim808 join network error");
delay(2000);
}
//************ Successful DHCP ****************
Serial.print("IP Address is ");
Serial.println(sim808.getIPAddress());
//*********** Establish a TCP connection ************
if(!sim808.connect(TCP,"mbed.org", 80)) {
Serial.println("Connect error");
}else{
Serial.println("Connect mbed.org success");
}
//*********** Send a GET request *****************
Serial.println("waiting to fetch...");
sim808.send(http_cmd, sizeof(http_cmd)-1);
while (true) {
int ret = sim808.recv(buffer, sizeof(buffer)-1);
if (ret <= 0){
Serial.println("fetch over...");
break;
}
buffer[ret] = '\0';
Serial.print("Recv: ");
Serial.print(ret);
Serial.print(" bytes: ");
Serial.println(buffer);
break;
}
//************* Close TCP or UDP connections **********
sim808.close();
//*** Disconnect wireless connection, Close Moving Scene *******
sim808.disconnect();
}
void loop(){
}
but i dont seem to understand what goes on at a point of the code, what does the part below, mean in the code
while (true) {
int ret = sim808.recv(buffer, sizeof(buffer)-1);
if (ret <= 0){
Serial.println("fetch over...");
break;
}
buffer[ret] = '\0';
Serial.print("Recv: ");
Serial.print(ret);
Serial.print(" bytes: ");
Serial.println(buffer);
break;
}
with emphasis on int ret = sim808.recv(buffer, sizeof(buffer)-1); how is the value of ret gotten?
If you just open up the .h file in the library you will find that it is pretty well documented. Have a look at the declaration for the function you are asking about:
/** read data from socket
* #param socket socket
* #param buf buffer that will store the data read from socket
* #param len string length need to read from socket
* #returns bytes that actually read
*/
int recv(char* buf, int len);
It details exactly what each parameter is and what the return value is. Looks like it returns the number of bytes read.

getting ip address of a packet in pcap file

I am programming with 'winpcap', I read a ".pcap" file in my program and after that I want to get the Ip addresses of packets, I've wrote these code for getting ip addresses,here is the piece of my code:
struct sniff_ip {
u_char ip_vhl; /* version << 4 | header length >> 2 */
u_char ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src;
struct in_addr ip_dst; /* source and dest address */
struct sniff_tcp {
u_short th_sport; /* source port */
u_short th_dport; /* destination port */
u_int32_t th_seq; /* sequence number */
u_int32_t th_ack; /* acknowledgement number */};
and after that I read the file:
while (pcap_next_ex(handler, &header, &packet) >= 0)
{
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
printf("src port: %d dest port: %d \n", tcp->th_sport, tcp->th_dport);
fprintf(fp,"src port: %d dest port: %d \n", tcp->th_sport, tcp->th_dport);
printf("src address: %s dest address: %s \n", inet_ntoa(ip->ip_src), inet_ntoa(ip->ip_dst));
fprintf(fp,"src address: %s dest address: %s \n", inet_ntoa(ip->ip_src), inet_ntoa(ip->ip_dst));
printf("seq number: %u ack number: %u \n", (unsigned int)tcp-> th_seq, (unsigned int)tcp->th_ack);
fprintf(fp,"seq number: %u ack number: %u \n", (unsigned int)tcp-> th_seq, (unsigned int)tcp->th_ack);
but the source and Ip addresses are the same!!!and it print the source and destination port incorrect!!what is the problem?what should I do for it?plz help me.
Source and destination ports are in network byte order (big-endian). Use ntohs to get them in the correct byte order for your machine. Same goes for SEQ and ACK, use ntohl for those.
The size of the IP header might not always be 20, multiply the value of ip_hdr_len with 4 to get the actual size.
If your compiler supports bitfields you can use them for your IP header declaration to make things easier:
struct sniff_ip {
u_char ip_hdr_len:4;
u_char ip_ver:4;
Fixed code:
while (pcap_next_ex(handler, &header, &packet) >= 0) {
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
if (ip->ip_p == 6 /* tcp protocol number */) {
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + ip->ip_hdr_len * 4);
u_short srcport = ntohs(tcp->th_sport);
u_short dstport = ntohs(tcp->th_dport);
printf("src port: %d dest port: %d \n", srcport, dstport);
char srcname[100];
strcpy(srcname, inet_ntoa(ip->ip_src));
char dstname[100];
strcpy(dstname, inet_ntoa(ip->ip_dst));
printf("src address: %s dest address: %s \n", srcname, dstname);
u_long seq = ntohl(tcp->th_seq);
u_long ack = ntohl(tcp->th_ack);
printf("seq number: %u ack number: %u \n", seq, ack);
}
}
Note that not every packet will contain TCP data, unless you applied a filter using pcap_compile and pcap_setfilter or can assure that the file you're reading contains only TCP packets. Therefore you might want to check the value of the IP headers protocol field to be 6 (TCP) as seen in the above code.
Also note that Wireshark by default displays relative SEQ and ACK numbers so they will not match with what you see there.
Structure packing should be fine.
First, make sure that the packets do, in fact, have an Ethernet header (do not assume they do!), by doing
if (pcap_datalink(handler) != DLT_EN10MB) {
fprintf(stderr, "%s is not an Ethernet capture\n",
{whatever the pathname of the file is});
exit(2);
}
after you've opened the capture file.
Then, you must make sure the packet really is an IPv4 packet, either by compiling the string "ip" as a filter, with pcap_compile(), and applying that to the file by calling pcap_setfilter() with handler and the compiled filter before you start reading, or by checking it in your read loop:
while (pcap_next_ex(handler, &header, &packet) >= 0) {
u_short ethertype;
/*
* For an Ethernet packet, the destination Ethernet
* address is in bytes 0 through 5, the source Ethernet
* address is in bytes 6 through 11, and the type/length
* field is in bytes 12 and 13.
*
* It's a big-endian value, so fetch the first byte, at
* an offset of 12, and put it in the upper 8 bits of
* the value, and then fetch the second byte, at an offset
* of 13, and put it in the lower 8 bits of the value.
*/
ethertype = (packet[12] << 8) | packet[13];
/*
* Now make sure it's the Ethernet type value for
* IPv4, which is 0x0800.
*/
if (ethertype != 0x0800) {
/*
* Skip this packet.
*/
continue;
}
/*
* Now we know it's an IPv4 packet, so process it as such.
*/
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
Note: do NOT use bitfields for the version and header length fields, as there is no guarantee that they will be in the correct order. Instead, calculate the header length using ip_vhl, e.g.
size_ip = (ip->ip_vhl & 0x0F) * 4;
How to pack structures depends on your compiler; for example, gcc uses #pragma pack(). Google for pack pragma gcc or pack pragma visual c or whichever compiler you're using.
You need to save the results of inet_ntoa if you're calling it twice to printf, like in
char *srcname=strdup(inet_ntoa(ip->ip_src));
char *dstname=strdup(inet_ntoa(ip->ip_dst));
printf("src address: %s dest address: %s \n", srcname, dstname);
free(srcname);
free(dstname);
(Note that you should add error checking, the function result pointers might be NULL).
inet_ntoa() returns the dots-and-numbers string in a static buffer that is overwritten with each call to the function.
http://www.retran.com/beej/inet_ntoaman.html
// We can print the ip address for source and destination like this.
while (currpos < InLen){
pcktcnt++;
currpos = ftello64(InRaw);
if (fread((char *) &pckthdr, sizeof(pckthdr), 1, InRaw) != 1) {
break;
}
if (fread((char *) &pcktbuf, pckthdr.caplen, 1, InRaw) != 1) {
break;
}
/* Find stream in file, count packets and get size (in bytes) */
if( isgetTCPIP(pcktbuf, &size_ip, &size_tcp,fp)){
/* Simple example code */
char srcIp[INET_ADDRSTRLEN]; /*or malloc it later*/
char dstIp[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(ip->ip_src), srcIp, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &(ip->ip_dst), dstIp, INET_ADDRSTRLEN);
fprintf("packet: %d, Src addr.: %s, Src port #: %d, Dest. addr: %s, Dest. port #: %d, \n",pcktcnt, srcIp, tcp->th_sport, dstIp, tcp->th_dport);
} // isgetTCPIP

Wireshark doesn't detect any packet sent. sendto return 0

I have been trying to send packets using raw socket in following code.This code I found somewhere in the internet. I created my own ipheader and udp header. The whole data packet is sent using sendto() function on raw socket. sendto() returns 0. Which means a packet of 0 length is sent out of it and hence even wireshark doesnt detect any packet. Where is my mistake?
// Must be run by root lol! Just datagram, no payload/data
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <cstdlib>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
// The packet length
#define PCKT_LEN 35
// Can create separate header file (.h) for all headers' structure
// The IP header's structure
struct ipheader {
unsigned char iph_ihl:4, iph_ver:4;
unsigned char iph_tos;
unsigned short int iph_len;
unsigned short int iph_ident;
unsigned char iph_flag;
unsigned short int iph_offset;
unsigned char iph_ttl;
unsigned char iph_protocol;
unsigned short int iph_chksum;
unsigned int iph_sourceip;
unsigned int iph_destip;
};
// UDP header's structure
struct udpheader {
unsigned short int udph_srcport;
unsigned short int udph_destport;
unsigned short int udph_len;
unsigned short int udph_chksum;
};
// total udp header length: 8 bytes (=64 bits)
// Function for checksum calculation. From the RFC,
// the checksum algorithm is:
// "The checksum field is the 16 bit one's complement of the one's
// complement sum of all 16 bit words in the header. For purposes of
// computing the checksum, the value of the checksum field is zero."
unsigned short csum(unsigned short *buf, int nwords)
{ //
unsigned long sum;
for(sum=0; nwords>0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
// Source IP, source port, target IP, target port from the command line arguments
int main(int argc, char *argv[])
{
int sd;
// No data/payload just datagram
char buffer[PCKT_LEN];
// Our own headers' structures
struct ipheader *ip = (struct ipheader *) buffer;
struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct ipheader));
// Source and destination addresses: IP and port
struct sockaddr_in sin, din;
int one = 1;
const int *val = &one;
memset(buffer, 0, PCKT_LEN);
if(argc != 5)
{
printf("- Invalid parameters!!!\n");
printf("- Usage %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
exit(-1);
}
// Create a raw socket with UDP protocol
sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
if(sd < 0)
{
perror("socket() error");
// If something wrong just exit
exit(-1);
}
else
printf("socket() - Using SOCK_RAW socket and UDP protocol is OK.\n");
// The source is redundant, may be used later if needed
// The address family
sin.sin_family = AF_INET;
din.sin_family = AF_INET;
// Port numbers
sin.sin_port = htons(atoi(argv[2]));
din.sin_port = htons(atoi(argv[4]));
// IP addresses
sin.sin_addr.s_addr = inet_addr(argv[1]);
din.sin_addr.s_addr = inet_addr(argv[3]);
// Fabricate the IP header or we can use the
// standard header structures but assign our own values.
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16; // Low delay
ip->iph_len = sizeof(struct ipheader) + sizeof(struct udpheader);
ip->iph_ident = htons(54321);
ip->iph_ttl = 64; // hops
ip->iph_protocol = 17; // UDP
// Source IP address, can use spoofed address here!!!
ip->iph_sourceip = inet_addr(argv[1]);
// The destination IP address
ip->iph_destip = inet_addr(argv[3]);
// Fabricate the UDP header. Source port number, redundant
udp->udph_srcport = htons(atoi(argv[2]));
// Destination port number
udp->udph_destport = htons(atoi(argv[4]));
udp->udph_len = htons(sizeof(struct udpheader));
// Calculate the checksum for integrity
ip->iph_chksum = csum((unsigned short *)buffer, sizeof(struct ipheader) + sizeof(struct udpheader));
// Inform the kernel do not fill up the packet structure. we will build our own...
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
{
perror("setsockopt() error");
exit(-1);
}
else
printf("setsockopt() is OK.\n");
// Send loop, send for every 2 second for 100 count
printf("Trying...\n");
printf("Using raw socket and UDP protocol\n");
printf("Using Source IP: %s port: %u, Target IP: %s port: %u.\n", argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));
int count;
int i;
for(count = 1; count <=20; count++)
{
if(i = sendto(sd, buffer, PCKT_LEN, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
// Verify
{
perror("sendto() error");
exit(-1);
}
else
{
printf("Count #%u - sendto() is OK. Data Length#%d\n", count,i);
sleep(2);
}
}
close(sd);
return 0;
}
Aha! I've got at least part of it.
i = sendto(sd, buffer, PCKT_LEN, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0
is the same as
i = (sendto(sd, buffer, PCKT_LEN, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
you probably want:
(i = sendto(sd, buffer, PCKT_LEN, 0, (struct sockaddr *)&sin, sizeof(sin))) < 0
You may want to:
Turn on warnings in your compiler - at least if you use gcc, that should give you a warning for comparing and assigning in the same if-statement.
Retry with the fixed code.
I'm sure there may be other problems in your code too - I'm no network expert.
It is really hard to read this piece of code and to understand what and why you're doing. So I can recoomend you look at my piece of code: dhcp client implementation
Look at function getSock() to see how socket is created, and on function talker() on how to form and send completed packet.
Local IP header structure is wrong... my suggestion is to include the IP header provided with your distro (are you using linux? don't you?).
What i did is just include linux/ip.h, rename ipheader structure reference to iphdr, and rename the ip header fields according to the structure described in the latter file.
I tried to sniff packets with tcpdump and it works now (i didn't try with wireshark but it must work too)
Try this fixed code:
// Must be run by root lol! Just datagram, no payload/data
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/udp.h>
#include <linux/ip.h>
// The packet length
#define PCKT_LEN 35
// UDP header's structure
struct udpheader {
unsigned short int udph_srcport;
unsigned short int udph_destport;
unsigned short int udph_len;
unsigned short int udph_chksum;
};
// total udp header length: 8 bytes (=64 bits)
// Function for checksum calculation. From the RFC,
// the checksum algorithm is:
// "The checksum field is the 16 bit one's complement of the one's
// complement sum of all 16 bit words in the header. For purposes of
// computing the checksum, the value of the checksum field is zero."
unsigned short csum(unsigned short *buf, int nwords)
{ //
unsigned long sum;
for(sum=0; nwords>0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
// Source IP, source port, target IP, target port from the command line arguments
int main(int argc, char *argv[])
{
int sd;
// No data/payload just datagram
char buffer[PCKT_LEN];
// Our own headers' structures
struct iphdr *ip = (struct iphdr *) buffer;
struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct iphdr));
// Source and destination addresses: IP and port
struct sockaddr_in sin, din;
int one = 1;
const int *val = &one;
memset(buffer, 0, PCKT_LEN);
if(argc != 5)
{
printf("- Invalid parameters!!!\n");
printf("- Usage %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
exit(-1);
}
// Create a raw socket with UDP protocol
sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
if(sd < 0)
{
perror("socket() error");
// If something wrong just exit
exit(-1);
}
else
printf("socket() - Using SOCK_RAW socket and UDP protocol is OK.\n");
// The source is redundant, may be used later if needed
// The address family
sin.sin_family = AF_INET;
din.sin_family = AF_INET;
// Port numbers
sin.sin_port = htons(atoi(argv[2]));
din.sin_port = htons(atoi(argv[4]));
// IP addresses
sin.sin_addr.s_addr = inet_addr(argv[1]);
din.sin_addr.s_addr = inet_addr(argv[3]);
// Fabricate the IP header or we can use the
// standard header structures but assign our own values.
ip->ihl = 5;
ip->version = 4;
ip->tos = 16; // Low delay
ip->tot_len = sizeof(struct iphdr) + sizeof(struct udpheader);
ip->id = htons(54321);
ip->ttl = 64; // hops
ip->protocol = 17; // UDP
// Source IP address, can use spoofed address here!!!
ip->saddr = inet_addr(argv[1]);
// The destination IP address
ip->daddr = inet_addr(argv[3]);
// Fabricate the UDP header. Source port number, redundant
udp->udph_srcport = htons(atoi(argv[2]));
// Destination port number
udp->udph_destport = htons(atoi(argv[4]));
udp->udph_len = htons(sizeof(struct udpheader));
// Calculate the checksum for integrity
ip->check = csum((unsigned short *)buffer, sizeof(struct iphdr) + sizeof(struct udpheader));
// Inform the kernel do not fill up the packet structure. we will build our own...
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
{
perror("setsockopt() error");
exit(-1);
}
else
printf("setsockopt() is OK.\n");
// Send loop, send for every 2 second for 100 count
printf("Trying...\n");
printf("Using raw socket and UDP protocol\n");
printf("Using Source IP: %s port: %u, Target IP: %s port: %u.\n", argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));
int count;
int i;
for(count = 1; count <=20; count++)
{
if((i = sendto(sd, buffer, PCKT_LEN, 0, (struct sockaddr *)&sin, sizeof(sin))) < 0)
// Verify
{
perror("sendto() error");
exit(-1);
}
else
{
printf("Count #%u - sendto() is OK. Data Length# %d\n", count,i);
sleep(2);
}
}
close(sd);
return 0;
}
I'm guessing you based that on this example code, which has multiple fatal bugs. It has wasted many hours of my life.
But to answer this specific question (and to help anyone else who is unfortunate enough to try to use that code), the bug that prevents you from seeing the packets in wireshark is here:
sin.sin_addr.s_addr = inet_addr(argv[1]);
This sets the address used for sending the packet in sentdo() to the source address. Therefore, the packet is sent over the loopback interface, and it goes nowhere. (Wireshark or other capture tools will be able to see the packet if you capture the lo/loopback interface, fwiw.)
So the corrected line for this particular program is:
sin.sin_addr.s_addr = inet_addr(argv[3]);

Library like ENet, but for TCP?

I'm not looking to use boost::asio, it is overly complex for my needs.
I'm building a game that is cross platform, for desktop, iPhone and Android.
I found a library called ENet which is pretty much what I need, but it uses UDP which does not seem to support encryption and a few other things. Given that the game is an event driven card game, TCP seems like the right fit.
However, all I have found is WINSOCK / berkley sockets and bost::asio.
Here is a sample client server application with ENet:
#include <enet/enet.h>
#include <stdlib.h>
#include <string>
#include <iostream>
class Host
{
ENetAddress address;
ENetHost * server;
ENetHost* client;
ENetEvent event;
public:
Host()
:server(NULL)
{
enet_initialize();
setupServer();
}
void setupServer()
{
if(server)
{
enet_host_destroy(server);
server = NULL;
}
address.host = ENET_HOST_ANY;
/* Bind the server to port 1234. */
address.port = 1721;
server = enet_host_create (& address /* the address to bind the server host to */,
32 /* allow up to 32 clients and/or outgoing connections */,
2 /* allow up to 2 channels to be used, 0 and 1 */,
0 /* assume any amount of incoming bandwidth */,
0 /* assume any amount of outgoing bandwidth */);
}
void daLoop()
{
while(true)
{
/* Wait up to 1000 milliseconds for an event. */
while (enet_host_service (server, & event, 5000) > 0)
{
ENetPacket * packet;
switch (event.type)
{
case ENET_EVENT_TYPE_CONNECT:
printf ("A new client connected from %x:%u.\n",
event.peer -> address.host,
event.peer -> address.port);
/* Store any relevant client information here. */
event.peer -> data = "Client information";
/* Create a reliable packet of size 7 containing "packet\0" */
packet = enet_packet_create ("packet",
strlen ("packet") + 1,
ENET_PACKET_FLAG_RELIABLE);
/* Extend the packet so and append the string "foo", so it now */
/* contains "packetfoo\0" */
enet_packet_resize (packet, strlen ("packetfoo") + 1);
strcpy ((char*)& packet -> data [strlen ("packet")], "foo");
/* Send the packet to the peer over channel id 0. */
/* One could also broadcast the packet by */
/* enet_host_broadcast (host, 0, packet); */
enet_peer_send (event.peer, 0, packet);
/* One could just use enet_host_service() instead. */
enet_host_flush (server);
break;
case ENET_EVENT_TYPE_RECEIVE:
printf ("A packet of length %u containing %s was received from %s on channel %u.\n",
event.packet -> dataLength,
event.packet -> data,
event.peer -> data,
event.channelID);
/* Clean up the packet now that we're done using it. */
enet_packet_destroy (event.packet);
break;
case ENET_EVENT_TYPE_DISCONNECT:
printf ("%s disconected.\n", event.peer -> data);
/* Reset the peer's client information. */
event.peer -> data = NULL;
}
}
}
}
~Host()
{
if(server)
{
enet_host_destroy(server);
server = NULL;
}
atexit (enet_deinitialize);
}
};
class Client
{
ENetAddress address;
ENetEvent event;
ENetPeer *peer;
ENetHost* client;
public:
Client()
:peer(NULL)
{
enet_initialize();
setupPeer();
}
void setupPeer()
{
client = enet_host_create (NULL /* create a client host */,
1 /* only allow 1 outgoing connection */,
2 /* allow up 2 channels to be used, 0 and 1 */,
57600 / 8 /* 56K modem with 56 Kbps downstream bandwidth */,
14400 / 8 /* 56K modem with 14 Kbps upstream bandwidth */);
if (client == NULL)
{
fprintf (stderr,
"An error occurred while trying to create an ENet client host.\n");
exit (EXIT_FAILURE);
}
/* Connect to some.server.net:1234. */
enet_address_set_host (& address, "192.168.2.13");
address.port = 1721;
/* Initiate the connection, allocating the two channels 0 and 1. */
peer = enet_host_connect (client, & address, 2, 0);
if (peer == NULL)
{
fprintf (stderr,
"No available peers for initiating an ENet connection.\n");
exit (EXIT_FAILURE);
}
/* Wait up to 5 seconds for the connection attempt to succeed. */
if (enet_host_service (client, & event, 20000) > 0 &&
event.type == ENET_EVENT_TYPE_CONNECT)
{
std::cout << "Connection to some.server.net:1234 succeeded." << std::endl;
}
else
{
/* Either the 5 seconds are up or a disconnect event was */
/* received. Reset the peer in the event the 5 seconds */
/* had run out without any significant event. */
enet_peer_reset (peer);
puts ("Connection to some.server.net:1234 failed.");
}
}
void daLoop()
{
ENetPacket* packet;
/* Create a reliable packet of size 7 containing "packet\0" */
packet = enet_packet_create ("backet",
strlen ("backet") + 1,
ENET_PACKET_FLAG_RELIABLE);
/* Extend the packet so and append the string "foo", so it now */
/* contains "packetfoo\0" */
enet_packet_resize (packet, strlen ("backetfoo") + 1);
strcpy ((char*)& packet -> data [strlen ("backet")], "foo");
/* Send the packet to the peer over channel id 0. */
/* One could also broadcast the packet by */
/* enet_host_broadcast (host, 0, packet); */
enet_peer_send (event.peer, 0, packet);
/* One could just use enet_host_service() instead. */
enet_host_flush (client);
while(true)
{
/* Wait up to 1000 milliseconds for an event. */
while (enet_host_service (client, & event, 1000) > 0)
{
ENetPacket * packet;
switch (event.type)
{
case ENET_EVENT_TYPE_RECEIVE:
printf ("A packet of length %u containing %s was received from %s on channel %u.\n",
event.packet -> dataLength,
event.packet -> data,
event.peer -> data,
event.channelID);
/* Clean up the packet now that we're done using it. */
enet_packet_destroy (event.packet);
break;
}
}
}
}
~Client()
{
atexit (enet_deinitialize);
}
};
int main()
{
std::string a;
std::cin >> a;
if(a == "host")
{
Host host;
host.daLoop();
}
else
{
Client c;
c.daLoop();
}
return 0;
}
I looked at some socket tutorials and they seemed a bit too low level.
I just need something that abstracts away the platform (eg, no WINSOCKS) and that has basic ability to keep track of connected clients and send them messages.
Thanks
A late reply but maybe it will help someone else.
Encryption is a high level feature. TCP nor UDP alone does not support encryption by itself. They are both low level protocols. Actually, we could say that TCP is a higher level protocol compared to UDP, because TCP includes some advanced features which might be useful ... or not, depending on a project where it will be used.
ENet is good because it provides the benefits of both worlds - the reliability of TCP and the freedom and light weight of UDP. There is nothing wrong with the fact that ENet internally uses only UDP and not TCP, because ENet is able to provide almost everything that TCP does, and much more.
If you wish to have encryption, you will have to add it yourself, no matter if you chose TCP, UDP or ENet. So I suggest you to continue using ENet if you feel comfortable with it, and when you get your game up and running, you can add any encryption algorithm you wish, as long as you choose the same algorithm for both client and server. You can pick a 3rd party encryption library and just pass your network packets through it. ENet doesn't care, what data is being sent through it.
Maybe the following article will help with ENet:
Network Programming with ENet By Mike Diehl
and also take a look at the following Stackoverflow topic about encryption for small network packets:
Best practices for encrypting continuous/small UDP data
I heard Mordor have an SSL layer which can be used for network encryption.
clsocket is a great little TCP library, permissive open source license, Windows, Mac OSX, Linux:
https://github.com/DFHack/clsocket

What is the proper process for ICMP echo request/reply on unreachable destinations?

Goal:
I need to be able to ping a network switch to determine whether or not it is available. This is meant to tell the user that either the network cabling is unplugged, the network switch is unavailable, or some other problem lies within the network communication pathway. I realize this is not a comprehensive diagnosis tool, but something is better than nothing.
Design:
I planned on using ICMP with raw sockets to send five (5) ping messages to a particular address in IPv4 dot-notation. I will setup an ICMP filter on the socket and will not be creating my own IP header. Transmission of the ICMP will be through the sendto method and reception through the recvfrom method. This will occur on a single thread (though another thread can be used to break transmission and reception apart). Reception of a message will further be filtered by matching the ID of the received message to the ID that was transmitted. The ID stored will be the running process ID of the application. If an ICMP_ECHOREPLY message is received and the ID of the message and the stored ID match, then a counter is incremented until five (4) has been reached (the counter is zero-based). I will attempt to send a ping, wait for its reply, and repeat this process five (5) times.
The Problem:
After having implemented my design, whenever I ping a particular valid network address (say 192.168.11.15) with an active network participant, I receive ICMP_ECHOREPLY messages for each of the five (5) pings. However, whenever I ping a valid network address (say 192.168.30.30) with inactive network participants (meaning no device is connected to the particular address), I get one (1) ICMP_DEST_UNREACH, and four (4) ICMP_ECHOREPLY messages. The ID in the reply messages match the ID stored within the software. Whenever I perform a 'ping 192.168.30.30' from the commandline, I get 'From 192.168.40.50 icmp_seq=xx Destination Host Unreachable'. Am I not supposed to be receiving ICMP_DEST_UNREACH messages instead of ICMP_ECHOREPLY messages?
The Code:
Ping.h:
#include <netinet/in.h>
#include <linux/ip.h>
#include <linux/ipmc.h>
#include <arpa/inet.h>
#include <cstdio>
#include <cstdlib>
#include <stdint.h>
#include <time.h>
#include <errno.h>
#include <string>
#include <cstring>
#include <netdb.h>
class Ping
{
public:
Ping(std::string host) : _host(host) {}
~Ping() {}
void start()
{
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if(sock < 0)
{
printf("Failed to create socket!\n");
close(sock);
exit(1);
}
setuid(getuid());
sockaddr_in pingaddr;
memset(&pingaddr, 0, sizeof(sockaddr_in));
pingaddr.sin_family = AF_INET;
hostent *h = gethostbyname(_host.c_str());
if(not h)
{
printf("Failed to get host by name!\n");
close(sock);
exit(1);
}
memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr));
// Set the ID of the sender (will go into the ID of the echo msg)
int pid = getpid();
// Only want to receive the following messages
icmp_filter filter;
filter.data = ~((1<<ICMP_SOURCE_QUENCH) |
(1<<ICMP_DEST_UNREACH) |
(1<<ICMP_TIME_EXCEEDED) |
(1<<ICMP_REDIRECT) |
(1<<ICMP_ECHOREPLY));
if(setsockopt(sock, SOL_RAW, ICMP_FILTER, (char *)&filter, sizeof(filter)) < 0)
{
perror("setsockopt(ICMP_FILTER)");
exit(3);
}
// Number of valid echo receptions
int nrec = 0;
// Send the packet
for(int i = 0; i < 5; ++i)
{
char packet[sizeof(icmphdr)];
memset(packet, 0, sizeof(packet));
icmphdr *pkt = (icmphdr *)packet;
pkt->type = ICMP_ECHO;
pkt->code = 0;
pkt->checksum = 0;
pkt->un.echo.id = htons(pid & 0xFFFF);
pkt->un.echo.sequence = i;
pkt->checksum = checksum((uint16_t *)pkt, sizeof(packet));
int bytes = sendto(sock, packet, sizeof(packet), 0, (sockaddr *)&pingaddr, sizeof(sockaddr_in));
if(bytes < 0)
{
printf("Failed to send to receiver\n");
close(sock);
exit(1);
}
else if(bytes != sizeof(packet))
{
printf("Failed to write the whole packet --- bytes: %d, sizeof(packet): %d\n", bytes, sizeof(packet));
close(sock);
exit(1);
}
while(1)
{
char inbuf[192];
memset(inbuf, 0, sizeof(inbuf));
int addrlen = sizeof(sockaddr_in);
bytes = recvfrom(sock, inbuf, sizeof(inbuf), 0, (sockaddr *)&pingaddr, (socklen_t *)&addrlen);
if(bytes < 0)
{
printf("Error on recvfrom\n");
exit(1);
}
else
{
if(bytes < sizeof(iphdr) + sizeof(icmphdr))
{
printf("Incorrect read bytes!\n");
continue;
}
iphdr *iph = (iphdr *)inbuf;
int hlen = (iph->ihl << 2);
bytes -= hlen;
pkt = (icmphdr *)(inbuf + hlen);
int id = ntohs(pkt->un.echo.id);
if(pkt->type == ICMP_ECHOREPLY)
{
printf(" ICMP_ECHOREPLY\n");
if(id == pid)
{
nrec++;
if(i < 5) break;
}
}
else if(pkt->type == ICMP_DEST_UNREACH)
{
printf(" ICMP_DEST_UNREACH\n");
// Extract the original data out of the received message
int offset = sizeof(iphdr) + sizeof(icmphdr) + sizeof(iphdr);
if(((bytes + hlen) - offset) == sizeof(icmphdr))
{
icmphdr *p = reinterpret_cast<icmphdr *>(inbuf + offset);
id = ntohs(p->un.echo.id);
if(origid == pid)
{
printf(" IDs match!\n");
break;
}
}
}
}
}
}
printf("nrec: %d\n", nrec);
}
private:
int32_t checksum(uint16_t *buf, int32_t len)
{
int32_t nleft = len;
int32_t sum = 0;
uint16_t *w = buf;
uint16_t answer = 0;
while(nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if(nleft == 1)
{
*(uint16_t *)(&answer) = *(uint8_t *)w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
answer = ~sum;
return answer;
}
std::string _host;
};
main.cpp:
#include "Ping.h"
int main()
{
// Ping ping("192.168.11.15");
Ping ping("192.168.30.30");
ping.start();
while(1) sleep(10);
}
In order to compile, just type 'g++ main.cpp -o ping' into the command-line of a Linux box, and it should compile (that is, if all of the source code is installed).
Conclusion:
Can anyone tell me why I am receiving one (1) ICMP_DEST_UNREACH and four (4) ICMP_ECHOREPLY messages from a device that isn't on that particular network address?
NOTE: You can change the network IP address from the main.cpp file. Just change the IP to a device that actually exists on your network or a device that doesn't exist on your network.
I'm also not interested in criticisms about coding style. I know it isn't pretty, has 'C' style casting mixed with C++ casts, has poor memory management, etc, but this is only prototype code. It isn't meant to be pretty.
Ok i found the error. Look at this two lines.
int bytes = sendto(sock, packet, sizeof(packet), 0, (sockaddr *)&pingaddr, sizeof(sockaddr_in));
bytes = recvfrom(sock, inbuf, sizeof(inbuf), 0, (sockaddr *)&pingaddr, (socklen_t *)&addrlen);
both functions uses pingaddr pointer as parameter, but this should avoided because in the sendto() function is used to point the destination IP of the icmp packet but in the recvfrom() is used to get back the IP of the host that's replying.
Let's say pingaddr is set with an IP not reachable. After your first ICMP_REQUEST the first gateway will reply to you with a ICMP_DEST_UNREACH and... here comes the error... when recvfrom is called, pingaddr structure will be overwritten with the IP of the gateway.
SO... from the second ping you'll be pointing to the gateway IP that, obviously, exists and will reply with a ICMP_ECHOREPLY.
SOLUTION:
avoid pass the same sockaddr_in structure pointer to both sendto() and recvfrom().