2010-10-22 19 views
24

Mi aplicación se ejecuta en CentOS 5.5. estoy usando conector directo para enviar datos:cómo vincular el socket sin procesar a una interfaz específica

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 enlazar a esta toma de interfaz de red específica (por ejemplo eth1)?

+0

¿Por qué querrías hacer eso? Su programa perderá la portabilidad a menos que esté seguro de que sus máquinas tendrán interfaces denominadas nombres predefinidos. –

+4

Es para dispositivos integrados, la portabilidad no es necesaria. Tengo 6 puertos Ethernet y necesito enviar datos usando la interfaz específica – Dima

Respuesta

36
char *opt; 
opt = "eth0"; 
setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, opt, 4); 

Primera línea: establecer la variable de

Segunda línea: decirle al programa qué interfaz se una a

Tercera línea: establecer las opciones de socket para el socket sd, la unión al dispositivo de opt, y como opt es de cuatro caracteres, establece 4 como la longitud.

setsockopt prototipo:

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

También, asegúrese de incluir el archivo de cabecera socket.h

+3

Gracias, funciona, pero con una pequeña modificación: interfaz ifreq; memset (& Interface, 0, sizeof (Interfaz)); strncpy (Interface.ifr_ifrn.ifrn_name, "eth1", IFNAMSIZ); if (setsockopt (sd, SOL_SOCKET, SO_BINDTODEVICE, & Interface, sizeof (Interface)) <0) { close (sd); // Error } – Dima

+0

SO_BINDTODEVICE solo funciona si ejecuta como root, ¿verdad? (en Linux al menos) – sep332

+0

Extraño parece requerir una estructura ifreq, cuando socket (7) que la opción pasada es Zstring de longitud variable ... –

14

Como se mencionó anteriormente, la cosa correcta que hacer es usar el 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, si bien es bueno para obligar a la toma de una interfaz, no tiene sentido utilizar INADDR_ANY como la dirección IP de 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 cambio, he especificado una dirección IP específica a la interfaz que se utiliza (una VLAN privada). Esto también corrigió 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 
+1

¿Dónde se especifica que use 'struct ifreq'? Mi página man dice "la opción pasada es una cadena de nombre de interfaz terminada en nulo de longitud variable" – Bryan

+3

El problema que sugiere (INADDR_ANY para sockets SOCK_STREAM) no ocurre para el póster original, que estaba usando SOCK_RAW. –

Cuestiones relacionadas