Sockets en windows 7 con winsock y WinPcap en C

Iniciado por luthorgelt, 13 Enero 2013, 18:24 PM

0 Miembros y 1 Visitante están viendo este tema.

luthorgelt

Estoy desarrollando una pequeña aplicación en el que un dispositivo me envía un paquete UDP y me gustaría saber porque si los captura con winpcap y no con winsock de windows.

Mi intención es desarrollar la aplicación sin añadirle la librería winpcap. Os dejo el código de las dos aplicaciones.


#include <winsock.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void error(const char *msg)
{
   perror(msg);
   exit(1);
}

int main(int argc, char *argv[])
{
  WSADATA wsda;
  SOCKET s;
  SOCKADDR_IN addr, remote_addr;
  u_short iPort = 12134;
  int i, ret, iRemoteAddrLen;
  char hex[16] = "123456789ABCDEF";
  char szMessage[512], szMessageString[512*3];

  WSAStartup(MAKEWORD(2,2), &wsda);
   s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  //s = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
 
  if(s == SOCKET_ERROR)
  {
     printf("Error\nCall to socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); failed with:\n%d\n", WSAGetLastError());
     exit(1);
  }

  addr.sin_family = AF_INET;
  addr.sin_port = htons(iPort);
  addr.sin_addr.s_addr = INADDR_ANY;

  if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR)
  {
     printf("Error\nCall to bind(s, (struct sockaddr *) &addr, sizeof(addr)); failed with:\n%d\n", WSAGetLastError());
     exit(1);
  }

  printf("Waiting for packets (Press Ctrl-C to exit)...\n");
  while(1)
  {
  iRemoteAddrLen = sizeof(remote_addr);
  ret = recvfrom(s, szMessage, sizeof(szMessage), 0, (struct sockaddr *) &remote_addr, &iRemoteAddrLen);

  if(ret == SOCKET_ERROR)
  {
 printf("Error\nCall to recvfrom(s, szMessage, sizeof(szMessage), 0, (struct sockaddr *) &remote_addr, &iRemoteAddrLen); failed with:\n%d\n", WSAGetLastError());
 exit(1);
  }

  for(i=0; i<ret; i++)
  {
  szMessageString[i*3+0] = hex[szMessage[i]>>4];
  szMessageString[i*3+1] = hex[szMessage[i]&0xF];
  szMessageString[i*3+2] = ' ';
  }
  szMessageString[i*3-1] = 0;

 printf("Received %d bytes from %s\n", ret, inet_ntoa(remote_addr.sin_addr));
  }

  closesocket(s);
  WSACleanup();

  return 0;

 }


#define HAVE_REMOTE
#include "pcap.h"
#include "remote-ext.h"

/* 4 bytes IP address */
typedef struct ip_address{
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
}ip_address;

/* IPv4 header */
typedef struct ip_header{
u_char ver_ihl; // Version (4 bits) + Internet header length (4 bits)
u_char tos; // Type of service
u_short tlen; // Total length
u_short identification; // Identification
u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits)
u_char ttl; // Time to live
u_char proto; // Protocol
u_short crc; // Header checksum
ip_address saddr; // Source address
ip_address daddr; // Destination address
u_int op_pad; // Option + Padding
}ip_header;

/* UDP header*/
typedef struct udp_header{
u_short sport; // Source port
u_short dport; // Destination port
u_short len; // Datagram length
u_short crc; // Checksum
}udp_header;

/* prototype of the packet handler */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);


int main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
char source[10] = "rpcap://";
u_int netmask;
char packet_filter[] = "ip and udp";
struct bpf_program fcode;

/* Retrieve the device list */
if (pcap_findalldevs_ex(source, NULL, &alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}

/* Print the list */
for(d=alldevs; d; d=d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s)\n", d->description);
else
printf(" (No description available)\n");
}

if(i==0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -1;
}

printf("Enter the interface number (1-%d):",i);
scanf("%d", &inum);

if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}

/* Jump to the selected adapter */
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);

/* Open the adapter */
if ( (adhandle= pcap_open(d->name, // name of the device
65536, // portion of the packet to capture.
// 65536 grants that the whole packet will be captured on all the MACs.
1, // promiscuous mode
1000, // read timeout
NULL, // remote authentication
errbuf // error buffer
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}

/* Check the link layer. We support only Ethernet for simplicity. */
if(pcap_datalink(adhandle) != DLT_EN10MB)
{
fprintf(stderr,"\nThis program works only on Ethernet networks.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}

if(d->addresses != NULL)
/* Retrieve the mask of the first address of the interface */
netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
else
/* If the interface is without addresses we suppose to be in a C class network */
netmask=0xffffff;


//compile the filter
if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 )
{
fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}

//set the filter
if (pcap_setfilter(adhandle, &fcode)<0)
{
fprintf(stderr,"\nError setting the filter.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}

printf("\nlistening on %s...\n", d->description);

/* At this point, we don't need any more the device list. Free it */
pcap_freealldevs(alldevs);

/* start the capture */
pcap_loop(adhandle, 0, packet_handler, NULL);

return 0;
}

/* Callback function invoked by libpcap for every incoming packet */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
struct tm ltime;
char timestr[16];
ip_header *ih;
udp_header *uh;
u_int ip_len;
u_short sport,dport;
time_t local_tv_sec;

/*
* Unused variable
*/
(VOID)(param);

/* convert the timestamp to readable format */
local_tv_sec = header->ts.tv_sec;
//localtime(&ltime, &local_tv_sec);
strftime( timestr, sizeof timestr, "%H:%M:%S", &ltime);

/* print timestamp and length of the packet */
printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);

/* retireve the position of the ip header */
ih = (ip_header *) (pkt_data +
14); //length of ethernet header

/* retireve the position of the udp header */
ip_len = (ih->ver_ihl & 0xf) * 4;
uh = (udp_header *) ((u_char*)ih + ip_len);

/* convert from network byte order to host byte order */
sport = ntohs( uh->sport );
dport = ntohs( uh->dport );

/* print ip addresses and udp ports */
printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d\n",
ih->saddr.byte1,
ih->saddr.byte2,
ih->saddr.byte3,
ih->saddr.byte4,
sport,
ih->daddr.byte1,
ih->daddr.byte2,
ih->daddr.byte3,
ih->daddr.byte4,
dport);
}


Mientras que la aplicación con winsock no me captura nada, la aplicación con winpcap me muestra:

.175848 len:47 192.168.0.176.12134 -> 192.168.0.150.12134
.177304 len:47 192.168.0.176.12134 -> 192.168.0.150.12134
.180558 len:47 192.168.0.176.12134 -> 192.168.0.150.12134
.182848 len:47 192.168.0.176.12134 -> 192.168.0.150.12134

He utilizado el compilador Mingw y la herramienta de desarrollo Netbeans 7.1.1

Por cierto, estos codigos los he encontrado en Internet.

luthorgelt

Sigo intentando descubrir porque no captura algo que deberia hacerlo con facilidad, ya que no estoy enviando nada a otra ip, sino a la del mismo pc. Quizas por la longitud de los paquetes?
He comprobado el estado del paquete con wireshark y no me dice nada fuera de lo comun.

Es extraño.

Hay otra forma de hacerlo??, que es lo que bloquea la captura??.




Vaagish

Hola luthorgelt, pudiste resolver el problema ? Hasta donde yo tengo entendido winsock ya no funciona en win 7,, probaste con descargar la el winsock ?

naderST

#3
http://msdn.microsoft.com/en-us/library/windows/desktop/ms740120(v=vs.85).aspx Viendo el ejemplo en la parte que llamas a bind, en el ejemplo le colocan htonl(INADDR_ANY) no se hasta que punto afecta esto, pero es el único detalle que pude observar

EDIT:

Olvídalo al parecer no hace ninguna diferencia.