2010-10-22 13 views
24

La mia applicazione è in esecuzione su CentOS 5.5. Sto utilizzando socket raw per inviare i dati:come associare il socket raw all'interfaccia specifica

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 
} 

Come posso associare questa presa per specifica interfaccia di rete (ad esempio eth1)?

+0

Perché vuoi farlo? Il tuo programma perderà la portabilità a meno che tu non sia sicuro che le tue macchine avranno interfacce chiamate i nomi predefiniti. –

+4

È per dispositivo incorporato, la portabilità non è necessaria. Ho 6 porte Ethernet e ho bisogno di inviare dati utilizzando l'interfaccia specifica – Dima

risposta

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

Prima riga: impostare la variabile

Seconda riga: indicare al programma quale interfaccia per l'associazione a

Terza riga: impostare le opzioni di socket per lo zoccolo sd, il legame con il dispositivo opt, e dal momento che opt è lungo quattro caratteri, impostare 4 come lunghezza.

setsockopt prototipo:

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

Inoltre, assicuratevi di includere il file di intestazione socket.h

+3

Grazie, funziona, ma con una piccola modifica: interfaccia ifreq; memset (& Interface, 0, sizeof (Interface)); strncpy (Interface.ifr_ifrn.ifrn_name, "eth1", IFNAMSIZ); if (setsockopt (sd, SOL_SOCKET, SO_BINDTODEVICE, & Interface, sizeof (Interface)) <0) { close (sd); // Errore } – Dima

+0

SO_BINDTODEVICE funziona solo se si esegue come root, giusto? (almeno su Linux) – sep332

+0

Strano sembra richiedere la struttura ifreq, quando socket (7) che l'opzione passata è Zstring a lunghezza variabile ... –

14

Come accennato in precedenza, la cosa giusta da fare è utilizzare il struct ifreq per specificare il nome dell'interfaccia. Ecco il mio esempio di codice.

#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)); 

Vorrei anche aggiungere che dal punto di vista della sicurezza, mentre è bene di impegnare la presa a un'interfaccia, che non ha senso usare INADDR_ANY come l'indirizzo IP di ascolto. In questo modo, la porta apparirà aperta in netstat su tutte le interfacce di rete.

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 

Invece, ho specificato un indirizzo IP specifico per l'interfaccia utilizzata (una VLAN privata). Anche questo ha corretto l'output 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

Dove è specificato che si usi 'struct ifreq'? La mia pagina man dice "l'opzione passata è una stringa di nome dell'interfaccia a terminazione nulla a lunghezza variabile" – Bryan

+3

Il problema suggerito (INADDR_ANY per i socket SOCK_STREAM) non si verifica per il poster originale, che stava usando SOCK_RAW. –

Problemi correlati