2010-10-22 114 views
24

我的應用程序正在CentOS 5.5上運行。 我使用原始套接字發送數據:如何將原始套接字綁定到特定接口

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 
} 

我如何可以綁定這個套接字到特定的網絡接口(比如eth1的)?

+0

你爲什麼要這麼做?除非您確定您的計算機將具有名爲預定義名稱的接口,否則您的程序將失去可移植性。 – 2010-10-22 16:52:44

+4

這是嵌入式設備,不需要攜帶便攜性。 我有6個以太網端口,我需要使用特定的接口發送數據 – Dima 2010-10-22 17:47:24

回答

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

第一行:建立了你的變量

下聯:告訴綁定到

其接口程序

第三行:設置套接字選項套接字sd,結合設備opt,並且由於opt是長度爲4個字符長度的集合4。

setsockopt的原型:

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

此外,請確保您包含socket.h中的頭文件

+3

謝謝,它的工作,但有一個小的修改: ifreq接口; memset(&Interface,0,sizeof(Interface)); strncpy(Interface.ifr_ifrn.ifrn_name,「eth1」,IFNAMSIZ);如果(setsockopt(sd,SOL_SOCKET,SO_BINDTODEVICE,&Interface,sizeof(Interface))<0) close(sd); //錯誤 } – Dima 2010-10-22 20:14:36

+0

SO_BINDTODEVICE只適用於以root身份運行,對不對? (至少在Linux上) – sep332 2012-11-27 21:29:31

+0

奇怪的是它似乎需要ifreq結構,當socket(7)傳遞的選項是可變長度的Zstring ... – 2013-01-14 07:53:31

14

正如前面提到的,做正確的事情是使用struct ifreq指定接口名稱。這是我的代碼示例。

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

我還想補充一點,從安全角度來看,雖然這是很好的套接字接口綁定,它沒有任何意義使用INADDR_ANY爲監聽的IP地址。這樣做會使端口在所有網絡接口上的netstat中顯示爲打開。

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 

取而代之,我指定了一個特定於正在使用的接口(專用VLAN)的IP地址。這也固定了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

它在哪裏指定您使用'struct ifreq'?我的手冊頁上寫着「 傳遞選項是一個可變長度的以null結尾的接口名稱字符串」 – Bryan 2016-02-18 14:15:38

+3

對於使用SOCK_RAW的原始發佈者,您建議的問題(對於SOCK_STREAM套接字,INADDR_ANY)不會發生。 – 2016-05-01 17:49:38

相關問題