¡Esta es una revisión vieja del documento!
Este artículo viene a que hará unos días se me pidió realizar un programa que replicase el tráfico de unos hosts a diversos servidores mediante UDP, es decir, unos clientes enviarían información a mi programa y este la repetería enviandola a otros clientes que ejecutaban un programa receptor de dicha información y la guardaban en Base de Datos.
Mi solución vino dada por un programilla en C# que recogía la información que le venía por un puerto y la repetía a las dirección:puerto que se indicaba en un archivo de configuración. Más o menos el código es el siguiente:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; namespace UDPRepiter { public class Server { public static void run() { int nBytes = Config.getNumBytes(); int port = Config.getPort(); int recv; byte[] data = new byte[nBytes]; IPEndPoint ipep = new IPEndPoint(IPAddress.Any, port); Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); sock.Bind(ipep); IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0); EndPoint tmpRemote = (EndPoint)sender; Console.WriteLine("Servidor obert!"); while (true) { Array.Clear(data, 0, data.Length); recv = sock.ReceiveFrom(data, ref tmpRemote); string rec = Encoding.ASCII.GetString(data).Trim().Replace("\0", ""); Console.WriteLine(">> " + rec); List<IPEndPoint> liep = Config.getClients(); foreach (IPEndPoint iep in liep) { Server.send(iep, data); Console.WriteLine(String.Format("{1} << {0}", rec, iep.ToString())); } } } public static void send(IPEndPoint ipep, byte[] data) { Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); server.SendTo(data, data.Length, SocketFlags.None, ipep); } } }
Pero apareció un problema, los clientes que recibían la información guardaban la dirección del orígen a partir de la comunicación UDP, es decir no guardaban la dirección de los emisores sino de la máquina que ejecutaba mi programa.
La solución que vino a mi mente fue realizar otro programa que los paquetes UDP que enviase los modificase colocando la dirección del emisor en este, es decir, no se podía utilizar sockets normales sino los llamados raw sockets.
Poco tiempo se tardó en desechar la tecnología .NET debido a su alto nivel y empecé a mirarme la implementación del protocolo UDP desde C. Primero en Windows y luego más tarde en Linux, aunque el código es muy parecido en Windows se agrega una restricción a los raw sockets que a pesar que en Linux también existe, esta se arregla corriendo el programa en modo root.
El código que tras estudiar bastante llegué a implementar:
#define SIZE_DATA 20 #define MYUDP #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> struct ipheader { unsigned char ip_hl:4; unsigned char ip_v:4; unsigned char ip_tos; unsigned short int ip_len; unsigned short int ip_id; unsigned short int ip_off; unsigned char ip_ttl; unsigned char ip_p; unsigned short int ip_check; unsigned int ip_src; unsigned int ip_dst; }; struct udpheader { unsigned short int uh_sport; unsigned short int uh_dport; unsigned short int uh_len; unsigned short int uh_check; }; unsigned short int checksum (unsigned short *buffer, int nwords) { unsigned long sum; for (sum = 0; nwords > 0; nwords--) sum += *buffer++; sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); return ~sum; } typedef unsigned short u16; typedef unsigned long u32; u16 checksum2 (u16 buff[], u16 len_header) { u16 word16; u32 sum = 0; u16 i; for (i=0; i<len_header; i=i+2) { word16 = ((buff[i]<<8)&0xFF00)+(buff[i+1]&0xFF); sum = sum + (u32) word16; } while (sum>>16) sum = (sum & 0xFFFF) + (sum >> 16); sum = ~sum; return (u16)sum; } int main () { int sock; struct sockaddr_in addr; char datagram[4096]; unsigned char data [SIZE_DATA]; int sizeIp, sizeUdp, sizeData; int sendResult; #ifdef UDP sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); #else sock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); int o = 1; if (setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&o,sizeof(o)) == -1) { perror("setsockopt()"); return; } #endif if (sock == -1) { perror ("Error en socket: "); return; } addr.sin_family = AF_INET; addr.sin_port = htons(1981); addr.sin_addr.s_addr = inet_addr("172.17.2.127"); sizeIp = sizeof(struct ipheader); sizeUdp = sizeof(struct udpheader); // Aquí habría que sumarle SIZE_DATA sizeData = SIZE_DATA; struct ipheader *iph = (struct ipheader *)datagram; struct udpheader *udph = (struct udpheader *)(datagram + sizeIp); // La cabecera UDP del datagrama empieza después de la IP memset (data, 65, SIZE_DATA); memset (datagram, 0, 4096); iph->ip_hl = 5; iph->ip_v = 4; iph->ip_tos = 0; iph->ip_len = sizeIp + sizeUdp; // aquí habría que sumarle SIZE_DATA iph->ip_id = htonl(1234); // Aleatorio iph->ip_off = 0; iph->ip_ttl = 255; iph->ip_p = 6; iph->ip_check = 0; iph->ip_src = inet_addr("127.0.0.1"); // Dirección que deseamos que reciba el receptor como de orígen iph->ip_dst = addr.sin_addr.s_addr; // Dirección destino udph->uh_sport = htonl(1234); // Puerto que deseamos que reciba el receptor como de orígen udph->uh_dport = htonl(1981); // Puerto destino udph->uh_len = sizeUdp; udph->uh_check = checksum2((unsigned short *)udph, sizeUdp); iph->ip_check = checksum2((unsigned short*) datagram, iph->ip_len); #ifdef UDP printf("Sending UDP\n"); sendResult = sendto (sock, (char*)data, 20, 0, &addr, sizeof(struct sockaddr_in)); #else printf("Sendig RAW\n"); sendResult = sendto (sock, (char*)datagram, iph->ip_len, 0, &addr, sizeof(struct sockaddr_in)); #endif if (sendResult == -1) perror("ERROR: "); else printf("SENT!\n"); return; }
No acaba de funcionar, envía pero parece ser no crea correctamente el paquete a pesar de que la implementación debe ser muy próxima a la correcta. Un paquete UDP contiene una cabecera IP y dentro de esta una UDP con los datos que se envían. La primera está representada por la variable iph y la segunda por udph, que tras crear el socket son rellenadas con los datos adecuados; el programa los rellena y luego lo envía a addr. Destaco las línias que están comentadas.
La cabecera IP tiene información como el destino y el orígen, cuanto mide el paquete, la versión de la ip o el puerto de orígen, también contiene la cabecera UDP que esta contiene el puerto de orígen y el de destino. Las dos contienen el tamaño que ocupan, la UDP sólo lo que ocupa esta cabecera y la IP lo que ocupa esta más la UDP, también contienen un valor de checksum (que para el UDP es opcional pudiendo ser 0), esta lo que hace es indicar que los datos son correctos. La copié de alguna web por ahí perdida y creo que no alcancé a implementarla correctamente es posible que sea una de las razones por la que este código envía pero no lo hace correctamente.
No acabó de salir en C, pero seguí investigando y descubrí que me podía ahorrar la declaración de las estructuras que representaban las cabeceras IP y UDP ya que están predefinidas como:
#include <arpa/inet.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/udp.h> ... struct iphdr *iph = (struct iphdr *)datagram; struct udphdr *udph = (struct udphdr *)(datagram + sizeof(struct iphdr));
Desesperado acabé mirando raw sockets en python, la implementación de estos imita la de C con las mismas funciones así que me aventuré a intentarlo con este nuevo lenguaje y conseguí mucho más que con el anterior. Por ejemplo, con las tres siguientes líneas ya podemos enviar un mensaje UDP a la ip 192.168.1.20 por el puerto 1982:
import socket s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) s.sendto("safd", ('192.168.1.20', 1982))
Estudiando un poco descubrí el paquete pyip que contiene las estructuras de las cabeceras IP y UDP además de unos cuantos métodos que te las ensamblan (colocan tamaño y checksum). La verdad es que no descubrí ninguna documentación y todo lo tube que sacar a partir de un ejemplo que ensamblaba una cabecera UDP pero es fácilmente deducible si ya has intentado implementarlo previamente en C:
import socket import udp import ip s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP) s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) ipp = ip.Packet() ipp.v = 4 ipp.hl = 5 ipp.id = 23 ipp.src = '1.2.3.4' ipp.dst = '192.168.1.20' ipp.ttl = 255 ipp.p = socket.IPPROTO_UDP udp_packet = udp.Packet() udp_packet.dport = 1982 udp_packet.sport = 33 udp_packet.data = "Dale a tu cuerpo alegria macarena que tu cuerpo" upacket = udp.assemble(udp_packet, 0) ipp.data = upacket packet = ip.assemble(ipp, 0) s.sendto(packet, ('192.168.1.20', 1982))
Este código lo que hace es:
setsockopt asignando 1 a la propiedad IP_HDRINCL del protocolo IP, esto significa que lo vamos a agregar nosotros, no que se agregará automáticamente.
Funciona perfectamente en Linux pero ha de ser lanzado en modo root. En Windows salta un error de seguridad.
No contento con esto y sabiendo que lo había conseguido desde Python pero no desde C intenté averiguar cual era el problema gracias a la aplicación Wireshark de Linux, la cual indica perfectamente el contenido de los paquetes enviados de una máquina a otra desglosando en cabeceras el paquete capturado. Podemos ver cómo lo hacía mal en la imágen 1 y que mi error no era debido a la función de checksum (que había cambiado 1000 veces) sino al cálculo del tamaño de la cabecera UDP (imágen 3), la imágen 2 muestra el envio del paquete en Python:
El código no enviaba aún datos, pero sí que enviaba un paquete correcto en Linux (como superusuario) que ya es algo. Ahora sólo falta que los envie y luego implementarlo en Windows (saltándose la restricción). El código es:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/udp.h> unsigned short checksum(unsigned short *ip, int len){ long sum = 0; /* assume 32 bit long, 16 bit short */ while(len > 1){ sum += *((unsigned short*) ip)++; if(sum & 0x80000000) /* if high order bit set, fold */ sum = (sum & 0xFFFF) + (sum >> 16); len -= 2; } if(len) /* take care of left over byte */ sum += (unsigned short) *(unsigned char *)ip; while(sum>>16) sum = (sum & 0xFFFF) + (sum >> 16); return ~sum; } int main(void) { int sock; int i; unsigned int buffer_size = sizeof(struct iphdr) + sizeof(struct udphdr); unsigned char buffer[buffer_size]; memset (buffer, 0, buffer_size); struct iphdr *ip = (struct iphdr *)buffer; struct udphdr *udp = (struct udphdr *)(buffer + sizeof(struct iphdr)); if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) == -1) { perror("socket()"); exit(EXIT_FAILURE); } int o = 1; if (setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&o,sizeof(o)) == -1) { perror("setsockopt()"); exit(EXIT_FAILURE); } ip->version = 4; ip->ihl = 5; ip->id = htonl(1981); ip->saddr = inet_addr("1.2.3.4"); ip->daddr = inet_addr("192.168.1.20"); ip->ttl = 255; ip->protocol = IPPROTO_UDP; ip->tot_len = buffer_size; ip->check = 0; udp->source = htons(1981); udp->dest = htons(1982); udp->len = htons(sizeof(struct udphdr)); udp->check = 0; ip->check = checksum((unsigned short*)ip, ip->tot_len); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = 1982; addr.sin_addr.s_addr = inet_addr("192.168.1.20"); if ((sendto(sock, buffer, buffer_size, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr_in))) == -1) { perror("send()"); exit(1); } for (i=0; i<buffer_size; i++) printf("%x", buffer[i]); printf("\n"); return 0; }
Programar con raw sockets en C desde Windows requiere de un esfuerzo extra, has de utilizar la librería WSA incluyendo Ws2_32.lib y haciendo una llamada que la inicialice, luego, tras imitar el código existente en Linux tendríamos esto:
#include <iostream> #include <winsock2.h> #include <ws2tcpip.h> struct iphdr { unsigned char ihl:4; unsigned char version:4; unsigned char tos; unsigned short int tot_len; unsigned short int id; unsigned short int off; unsigned char ttl; unsigned char protocol; unsigned short int check; unsigned int saddr; unsigned int daddr; }; struct udphdr { unsigned short int source; unsigned short int dest; unsigned short int len; unsigned short int check; }; unsigned short checksum(unsigned short *ip, int len){ long sum = 0; /* assume 32 bit long, 16 bit short */ while(len > 1){ sum += *((unsigned short*) ip)++; if(sum & 0x80000000) /* if high order bit set, fold */ sum = (sum & 0xFFFF) + (sum >> 16); len -= 2; } if(len) /* take care of left over byte */ sum += (unsigned short) *(unsigned char *)ip; while(sum>>16) sum = (sum & 0xFFFF) + (sum >> 16); return ~sum; } int initialize() { int t; WSADATA wsa_data; t = WSAStartup(MAKEWORD(1,1), &wsa_data); if(t != 0) return -1; else return 0; } void main () { int error; SOCKET sock; SOCKADDR_IN addr; struct iphdr *ip; struct udphdr *udp; unsigned int buffer_size; unsigned char sendBuf[2048]; memset(sendBuf,0,2048); initialize(); sock = socket(AF_INET,SOCK_RAW,IPPROTO_UDP); if (sock == SOCKET_ERROR) { printf ("error (2) : %d\n", WSAGetLastError()); system("pause"); return; } int on = 1; error = setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(const char*)&on,sizeof(on)); if (error == SOCKET_ERROR) { printf ("error (2) : %d\n", WSAGetLastError()); system("pause"); return; } ip = (struct iphdr *)sendBuf; udp = (struct udphdr *)(sendBuf + sizeof(struct iphdr)); buffer_size = sizeof(struct iphdr) + sizeof(struct udphdr); ip->version = 4; ip->ihl = 5; ip->id = htonl(1981); ip->saddr = inet_addr("1.2.3.4"); ip->daddr = inet_addr("192.168.1.20"); ip->ttl = 255; ip->protocol = IPPROTO_UDP; ip->tot_len = buffer_size; ip->check = 0; ip->off = 0; ip->ttl = 255; udp->source = htons(1981); udp->dest = htons(1982); udp->len = htons(sizeof(struct udphdr)); udp->check = 0; ip->check = checksum((unsigned short*)ip, ip->tot_len); addr.sin_family = AF_INET; addr.sin_port = 1982; addr.sin_addr.s_addr = inet_addr("192.168.1.20"); for(int i=0;i<buffer_size;i++) printf("%x",sendBuf[i]); printf("\n"); printf("4501c00000ff11caa71234c0a81147bd7be0800\n"); error = sendto(sock,(char*)sendBuf,buffer_size,0,(LPSOCKADDR)&addr,sizeof(SOCKADDR_IN)); if(error == SOCKET_ERROR) { printf ("error (3) : %d\n", WSAGetLastError()); system("pause"); return; } system("pause"); }
Aún así, este código no funciona, y es que Windows XP agrega seguridad en los raw sockets y para que funcione la línia de la ip orígen ha de ser correcta, algo así si se llama desde la máquina con ip 192.168.1.20:
ip->saddr = inet_addr("192.168.1.20");
Windows XP tiene este parche de seguridad pero no los demás (ni el 2003, ni el 2000…), por lo que el programilla podía funcionar. Al final se implementó para que pudiese enviar datos y el código quedó así:
#include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #include <string.h> #define SBUFFER 2048 struct iphdr { unsigned char ihl:4; unsigned char version:4; unsigned char tos; unsigned short int tot_len; unsigned short int id; unsigned short int off; unsigned char ttl; unsigned char protocol; unsigned short int check; unsigned int saddr; unsigned int daddr; }; struct udphdr { unsigned short int source; unsigned short int dest; unsigned short int len; unsigned short int check; }; unsigned short checksum(unsigned short *ip, int len){ long sum = 0; /* assume 32 bit long, 16 bit short */ while(len > 1){ sum += *((unsigned short*) ip)++; if(sum & 0x80000000) /* if high order bit set, fold */ sum = (sum & 0xFFFF) + (sum >> 16); len -= 2; } if(len) /* take care of left over byte */ sum += (unsigned short) *(unsigned char *)ip; while(sum>>16) sum = (sum & 0xFFFF) + (sum >> 16); return ~sum; } int initialize() { int t; WSADATA wsa_data; t = WSAStartup(MAKEWORD(1,1), &wsa_data); if(t != 0) return -1; else return 0; } void main () { int error; SOCKET sock; SOCKADDR_IN addr; struct iphdr *ip; struct udphdr *udp; unsigned int buffer_size = SBUFFER; unsigned char sendBuf[SBUFFER]; unsigned char *data; unsigned char myword[] = "hola"; memset(sendBuf, 0, SBUFFER); initialize(); sock = socket(AF_INET,SOCK_RAW,IPPROTO_UDP); if (sock == SOCKET_ERROR) { printf ("error (2) : %d\n", WSAGetLastError()); system("pause"); return; } int on = 1; error = setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(const char*)&on,sizeof(on)); if (error == SOCKET_ERROR) { printf ("error (2) : %d\n", WSAGetLastError()); system("pause"); return; } ip = (struct iphdr *)sendBuf; udp = (struct udphdr *)(sendBuf + sizeof(struct iphdr)); data = (unsigned char*)udp + sizeof(struct udphdr); memcpy(data, myword, sizeof(myword)); buffer_size = sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof (data); ip->version = 4; ip->ihl = 5; ip->id = htonl(1981); ip->saddr = inet_addr("172.17.2.104"); ip->daddr = inet_addr("172.17.2.127"); ip->ttl = 255; ip->protocol = IPPROTO_UDP; ip->tot_len = buffer_size; ip->check = 0; ip->off = 0; ip->ttl = 255; udp->source = htons(33); udp->dest = htons(1981); udp->len = htons(sizeof(struct udphdr) + sizeof(data)); udp->check = 0; ip->check = checksum((unsigned short*)ip, ip->tot_len); addr.sin_family = AF_INET; addr.sin_port = 1982; addr.sin_addr.s_addr = inet_addr("172.17.2.127"); printf("IP header: %d\nUDP header: %d\nData: %d\n", ip->tot_len, htons(udp->len), sizeof(data)); error = sendto(sock,(char*)sendBuf,buffer_size,0,(LPSOCKADDR)&addr,sizeof(SOCKADDR_IN)); if(error == SOCKET_ERROR) { printf ("error (3) : %d\n", WSAGetLastError()); system("pause"); return; } printf("Sended!\n"); system("pause"); }
La versión final del código es el siguiente:
#include <iostream> #include <fstream> #include <winsock2.h> #include <ws2tcpip.h> #include <string.h> #include <vector> #define SBUFFER 2048 using namespace std; struct iphdr { unsigned char ihl:4; unsigned char version:4; unsigned char tos; unsigned short int tot_len; unsigned short int id; unsigned short int off; unsigned char ttl; unsigned char protocol; unsigned short int check; unsigned int saddr; unsigned int daddr; }; struct udphdr { unsigned short int source; unsigned short int dest; unsigned short int len; unsigned short int check; }; struct host { unsigned long ip; unsigned short port; bool raw; }; struct config { unsigned short localPort; vector<host> hosts; }; struct msg_received { char* data; int lenghtData; unsigned long ip; int port; }; unsigned short checksum(unsigned short *ip, int len){ long sum = 0; while(len > 1){ sum += *((unsigned short*) ip)++; if(sum & 0x80000000) sum = (sum & 0xFFFF) + (sum >> 16); len -= 2; } if(len) sum += (unsigned short) *(unsigned char *)ip; while(sum>>16) sum = (sum & 0xFFFF) + (sum >> 16); return ~sum; } int initializeWSA() { int t; WSADATA wsa_data; t = WSAStartup(MAKEWORD(1,1), &wsa_data); if(t != 0) return -1; else return 0; } void initSockets (SOCKET* receiver, SOCKET* sender, SOCKET* raw_sender, config* conf) { int on; SOCKADDR_IN addr; memset(&addr, 0, sizeof(addr)); *sender = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (*sender == INVALID_SOCKET) cout << "Error creating sender socket : " << WSAGetLastError() << endl; *raw_sender = socket(AF_INET, SOCK_RAW, IPPROTO_UDP); if (*raw_sender == INVALID_SOCKET) cout << "Error creating raw socket : " << WSAGetLastError() << endl; on = 1; if (setsockopt(*raw_sender, IPPROTO_IP, IP_HDRINCL, (const char*)&on, sizeof(on)) == SOCKET_ERROR) cout << "Error setting raw options : " << WSAGetLastError() << endl; addr.sin_port = htons(conf->localPort); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; *receiver = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (*receiver == INVALID_SOCKET) cout << "Error creating receiver socket : " << WSAGetLastError() << endl; if (bind(*receiver, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) cout << "Error binding receiver socket : " << WSAGetLastError() << endl; } void sendRaw (SOCKET* raw_socket, msg_received* msg, host* dest) { SOCKADDR_IN addr; struct iphdr* ip; struct udphdr* udp; char buffer [SBUFFER]; char* buffer_data; int buffer_size; memset(buffer, 0, SBUFFER); ip = (struct iphdr *)buffer; udp = (struct udphdr *)(buffer + sizeof(struct iphdr)); buffer_data = (char*)udp + sizeof(struct udphdr); memcpy(buffer_data, msg->data, msg->lenghtData); buffer_size = sizeof(struct iphdr) + sizeof(struct udphdr) + msg->lenghtData; ip->version = 4; ip->ihl = 5; ip->id = htonl(1981); ip->saddr = msg->ip; ip->daddr = dest->ip; ip->ttl = 255; ip->protocol = IPPROTO_UDP; ip->tot_len = buffer_size; ip->check = 0; ip->off = 0; ip->ttl = 255; udp->source = htons(msg->port); udp->dest = htons(dest->port); udp->len = htons(sizeof(struct udphdr) + msg->lenghtData); udp->check = 0; ip->check = checksum((unsigned short*)ip, ip->tot_len); addr.sin_family = AF_INET; addr.sin_port = dest->port; addr.sin_addr.s_addr = dest->ip; in_addr ipAddr; char* tmp; char strDest[16]; char strMsg[16]; ipAddr.s_addr = dest->ip; tmp = inet_ntoa(ipAddr); memcpy(strDest, tmp, 16); ipAddr.s_addr = msg->ip; tmp = inet_ntoa(ipAddr); memcpy(strMsg, tmp, 16); cout << "> Raw sending to " << strDest << ":" << dest->port << " as " << strMsg << ":" << msg->port << endl; if (sendto(*raw_socket, (char*)buffer, buffer_size, 0, (LPSOCKADDR)&addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR) cout << "Error sending with raw socket : " << WSAGetLastError() << endl; } void sendNormal (SOCKET* sock, msg_received* msg, host* dest) { SOCKADDR_IN addr; memset(&addr, 0, sizeof(addr)); addr.sin_addr.s_addr = dest->ip; addr.sin_family = AF_INET; addr.sin_port = htons(dest->port); cout << "> Sending to " << inet_ntoa(addr.sin_addr) << ":" << dest->port << endl; int size = sendto(*sock, msg->data, msg->lenghtData, 0, (LPSOCKADDR)&addr, sizeof(SOCKADDR_IN)); if (size == -1) cout << "Error sending"; } void send (SOCKET* sender, SOCKET* raw_sender, msg_received* msg, config* conf) { host h; for (int i=0; i<conf->hosts.size(); i++) { h = conf->hosts.at(i); if (h.raw) sendRaw(raw_sender, msg, &h); else sendNormal(sender, msg, &h); } } void listen (SOCKET* receiver, msg_received* msg) { int size = 0; SOCKADDR_IN addr; int tmp = sizeof(addr); memset(&addr, 0, sizeof(addr)); do { size = recvfrom(*receiver, msg->data, SBUFFER, 0, (struct sockaddr*)&addr, &tmp); } while (size == -1); msg->ip = addr.sin_addr.s_addr; msg->lenghtData = size; msg->port = htons(addr.sin_port); in_addr ia; ia.s_addr = msg->ip; cout << "< Received (" << inet_ntoa(ia) << ":" << msg->port << ") : " << msg->data << endl; } void readConfig (config* conf) { char line[256]; host h; char* token; ifstream file; file.open("config.txt", ios::binary); file.getline(line, 256); conf->localPort = atoi(line); while (!file.eof()) { h = host(); file.getline(line, 256); token = strtok(line, " "); h.ip = inet_addr(token); token = strtok(NULL, " "); h.port = atoi(token); token = strtok(NULL, " "); h.raw = (token[0] == 42) ? true : false; conf->hosts.push_back(h); } file.close(); } void main () { SOCKET receiver, sender, raw_sender; config conf; char data[SBUFFER]; msg_received msg; msg.data = data; msg.ip = 0; msg.lenghtData = 0; cout << "Starting SuperUDPRepeater!" << endl; readConfig(&conf); initializeWSA(); initSockets(&receiver, &sender, &raw_sender, &conf); do { memset(data, 0, SBUFFER); listen(&receiver, &msg); send(&sender, &raw_sender, &msg, &conf); } while (1); return; }
Este lee un fichero en el que la primera línia es el puerto por el que escucha, y luego, las siguientes tienen separadas por un espacio:
1982 172.17.2.125 1983 - 172.17.2.127 1981 - 172.17.2.17 9991 * 172.17.2.207 2789 -