programing

원시 소켓을 특정 인터페이스에 바인딩하는 방법

lovejava 2023. 9. 11. 21:19

원시 소켓을 특정 인터페이스에 바인딩하는 방법

제 애플리케이션은 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)에 바인딩하려면 어떻게 해야 합니까?

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

첫번째 줄: 변수 설정

두 번째 줄: 바인딩할 인터페이스를 프로그램에 지정합니다.

3-5행: 인터페이스 이름의 길이를 구하고 크기가 너무 크지 않은지 확인합니다.

6라인: 소켓의 소켓 옵션 설정sd, 장치에 바인딩opt.

setsockopt 프로토타입:

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

또한, 당신은 다음을 포함해야 합니다.if.h,socket.h그리고.string.h머리글 파일

앞서 언급한 바와 같이, 올바른 작업은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  

대신 사용 중인 인터페이스에 특정한 IP 주소(전용 VLAN)를 지정했습니다.이것은 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  

소켓을 특정 인터페이스 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));
}

소켓을 특정 인터페이스 이름에 바인딩

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

bind_using_iface_ip, 어떤 항구에도 묶다0통과되어야 합니다.그리고 만약에.fdraw socket 그러면 포트를 통과해야 합니다.0. 이 바인딩 메커니즘은 raw, dgram 및 stream과 같은 모든 종류의 소켓에 대해 일반적입니다.

언급URL : https://stackoverflow.com/questions/3998569/how-to-bind-raw-socket-to-specific-interface