简体   繁体   English

如何将原始套接字绑定到特定接口

[英]how to bind raw socket to specific interface

My application is running on CentOS 5.5. 我的应用程序在CentOS 5.5上运行。 I'm using raw socket to send data: 我正在使用原始套接字发送数据:

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
}

How can I bind this socket to specific network interface (say eth1)? 如何将此套接字绑定到特定的网络接口(例如eth1)?

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

First line: set up your variable 第一行:设置变量

Second line: tell the program which interface to bind to 第二行:告诉程序要绑定哪个接口

Lines 3-5: get length of interface name and check if it's size not too big. 第3-5行:获取接口名称的长度,并检查它的大小是否太大。

Six line: set the socket options for socket sd , binding to the device opt . 六行:设置套接字sd的套接字选项,绑定到设备opt

setsockopt prototype: setsockopt原型:

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

Also, make sure you include the if.h , socket.h and string.h header files 另外,请确保包含if.hsocket.hstring.h头文件

As mentioned earlier, the correct thing to do is use the struct ifreq to specify the interface name. 如前所述,正确的做法是使用struct ifreq来指定接口名称。 Here is my code sample. 这是我的代码示例。

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

I would also like to add that from a security perspective, while it is good to bind the socket to an interface, it does not make sense to use INADDR_ANY as the listening IP address. 我还想从安全角度来看,虽然将套接字绑定到接口是好的,但使用INADDR_ANY作为侦听IP地址是没有意义的。 Doing so would make the port appear open in netstat on all network interfaces. 这样做会使端口在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  

Instead, I specified an IP address specific to the interface being used (a private VLAN). 相反,我指定了特定于所使用接口的IP地址(专用VLAN)。 This fixed the netstat output too: 这也修复了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  

Bind socket to specific interface IP address 将套接字绑定到特定接口IP地址

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

Bind socket to specific interface name 将套接字绑定到特定的接口名称

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

In bind_using_iface_ip , to bind to any port 0 should be passed. bind_using_iface_ip ,应该传递绑定到任何端口0 And also if the fd is raw socket then need to pass port as 0 . 而且如果fd是原始套接字,那么需要将端口传递为0 This bind mechanism is common for all kind of sockets like raw, dgram and stream. 这种绑定机制适用于所有类型的套接字,如raw,dgram和stream。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM