vlan tag configurar configuracion comandos cluster linux sockets networking network-programming raw-sockets

linux - tag - cómo vincular el socket sin formato a una interfaz específica



vlan linux (3)

Mi aplicación se ejecuta en CentOS 5.5. Estoy usando socket raw para enviar datos:

sd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if (sd < 0) { // Error } const int opt_on = 1; rc = setsockopt(m_SocketDescriptor, IPPROTO_IP, IP_HDRINCL, &opt_on, sizeof(opt_on)); if (rc < 0) { close(sd); // Error } struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = my_ip_address; if (sendto(m_SocketDescriptor, DataBuffer, (size_t)TotalSize, 0, (struct sockaddr *)&sin, sizeof(struct sockaddr)) < 0) { close(sd); // Error }

¿Cómo puedo vincular este socket a una interfaz de red específica (digamos eth1)?


Como se mencionó anteriormente, lo correcto es usar struct ifreq para especificar el nombre de la interfaz. Aquí está mi código de muestra.

#define SERVERPORT 5555 ... struct ifreq ifr; /* Create the socket */ sd = socket(AF_INET, SOCK_STREAM, 0); if (sd < 0) { printf("Error in socket() creation - %s", strerror(errno)); } /* Bind to eth1 interface only - this is a private VLAN */ memset(&ifr, 0, sizeof(ifr)); snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth1"); if ((rc = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr))) < 0) { perror("Server-setsockopt() error for SO_BINDTODEVICE"); printf("%s/n", strerror(errno)); close(sd); exit(-1); } /* bind to an address */ memset(&serveraddr, 0x00, sizeof(struct sockaddr_in)); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(SERVERPORT); serveraddr.sin_addr.s_addr = inet_addr("9.1.2.3"); int rc = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

También me gustaría añadir que desde una perspectiva de seguridad, aunque es bueno vincular el socket a una interfaz, no tiene sentido usar INADDR_ANY como la dirección IP que escucha. Si lo hace, el puerto aparecerá abierto en netstat en todas las interfaces de red.

Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name tcp 0 0 0.0.0.0:5555 0.0.0.0:* LISTEN 0 210898 26996/myserver

En su lugar, especifiqué una dirección IP específica para la interfaz que se utiliza (una VLAN privada). Esto también solucionó la salida netstat:

Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name tcp 0 0 9.1.2.3:5555 0.0.0.0:* LISTEN 0 210898 26996/myserver


Enlazar el socket a la dirección IP de la interfaz específica

int bind_using_iface_ip(int fd, char *ipaddr, uint16_t port) { struct sockaddr_in localaddr = {0}; localaddr.sin_family = AF_INET; localaddr.sin_port = htons(port); localaddr.sin_addr.s_addr = inet_addr(ipaddr); return bind(fd, (struct sockaddr*) &localaddr, sizeof(struct sockaddr_in)); }

Enlazar el socket al nombre de la interfaz específica

int bind_using_iface_name(int fd, char *iface_name) { return setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, iface_name, strlen(iface_name)) }

En bind_using_iface_ip , para enlazar a cualquier puerto 0 debe pasar. Y también si el fd es un socket sin formato, entonces debe pasar el puerto como 0 . Este mecanismo de enlace es común para todos los tipos de sockets, como raw, dgram y stream.


const char *opt; opt = "eth0"; const len = strnlen(opt, IFNAMSIZ); if (len == IFNAMESIZ) { fprintf(stderr, "Too long iface name"); return 1; } setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, opt, len);

Primera línea: configure su variable

Segunda línea: indique al programa qué interfaz vincular a

Líneas 3-5: obtener la longitud del nombre de la interfaz y comprobar si su tamaño no es demasiado grande.

Six line: establece las opciones de socket para socket sd , vinculando al dispositivo opt .

prototipo setsockopt:

int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);

Además, asegúrese de incluir los archivos de encabezado socket.h y string.h