2013-10-08 122 views
1

我有一个服务器与几个不同的IP地址。此时,每个IP都可以收到一个UDP请求,但它总是与请求者不喜欢的回复相同的IP。动态更改源IP地址

为了使长话短说,这是所有的基本代码:

int sock; 
socklen_t clilen; 
struct sockaddr_in serv_addr, cli_addr; 
memset((char*)&serv_addr, 0, sizeof(serv_addr)); 

sock = socket(AF_INET, SOCK_DGRAM, 0); 
serv_addr.sin_family = AF_INET; 
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
serv_addr.sin_port = htons(PORT); 
... 
recvfrom(sock, buffer, BUFLEN, 0, (struct sockaddr *)&cli_addr, &clilen); 
... 
sendto(sock, resData, resLen, 0, (struct sockaddr *)&cli_addr, sizeof(cli_addr)); 

我希望能够以某种方式指定IP用于发送回我的包(这可以为每个不同和每个请求),但我不知道如何以及如果这甚至可以使用套接字来完成。我在这个领域并不是那么有经验,所以我能得到的所有帮助都非常感谢。

编辑下面

我发现在这里接受的答案潜在的解决方案:How to re bind a udp socket in Linux

然而,新的问题出现了。我如何知道哪个IP /接口收到了请求?这样我可以使用该IP /接口进行响应。

+0

你的问题还不清楚。你的机器上有多个接口,并且你想每次都从不同的接口发送。或者你想欺骗IP地址到虚假的IP地址? – Salgar

+0

我有多个接口,我不想欺骗。 – user2215771

回答

0

我已经解决了我的问题,并在良好地解决方案必须公布!我没有使用SOCK_RAW,也没有将我的接口绑定到本地IP地址或类似地址。这是谷歌和一些计算器上的100页的混合,所以我有点难过,我没有保存链接,以发出正确的信用。

代码中可能存在明显的缺陷,因为我不是专家,但是这是我想出的解决方案,它的工作原理。我刚开始清理代码(当您尝试从100个不同的页面中合并它们时,它会变得杂乱无章)。不管怎么说,那就是:

接收部分:

int sock; 
socklen_t clilen; 
struct sockaddr_in serv_addr, cli_addr; 
char buffer[BUFLEN]; 

// Next 
memset((char*)&serv_addr, 0, sizeof(serv_addr)); 
sock = socket(AF_INET, SOCK_DGRAM, 0); 
serv_addr.sin_family = AF_INET; 
//serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
serv_addr.sin_port = htons(PORT); 

clilen = sizeof(cli_addr); 

if (bind(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { 
    error("ERROR on binding"); 
} 

bool opt = true; 
setsockopt(sock, IPPROTO_IP, IP_PKTINFO, (char *)&opt, sizeof(opt)); 

// Packet data will be saved in buffer 
bzero(buffer, BUFLEN); 
struct iovec vector; 
vector.iov_base = buffer; 
vector.iov_len = sizeof(buffer); 

struct msghdr msg; 
msg.msg_name = &cli_addr; 
msg.msg_namelen = sizeof(cli_addr); 
msg.msg_iov = &vector; 
msg.msg_iovlen = 1; 
int flags = 0; 

// Not sure what controlBuffer contains at this point 
char controlBuffer[1024]; 
msg.msg_control = controlBuffer; 
msg.msg_controllen = 1024; 

// Recv packet 
int bytes = ::recvmsg(sock, &msg, flags); 

struct cmsghdr *cmsg; 
struct in_pktinfo *dest_ip_ptr; 
int dest_ip = 0; 

// Loop through IP header messages 
cmsg = CMSG_FIRSTHDR(&msg); 
for (cmsg = CMSG_FIRSTHDR(&msg); 
    cmsg != NULL; 
    cmsg = CMSG_NXTHDR(&msg, cmsg)) 
{ 
    if (cmsg->cmsg_level != IPPROTO_IP || 
     cmsg->cmsg_type != IP_PKTINFO) 
    { 
     continue; 
    } 

    // Get IP (int) 
    struct in_pktinfo *dest_ip_ptr = (struct in_pktinfo*)CMSG_DATA(cmsg); 
    dest_ip = dest_ip_ptr->ipi_addr.s_addr; 
} 

// Format IP 
unsigned char ipParts[4]; 
ipParts[0] = dest_ip & 0xFF; 
ipParts[1] = (dest_ip >> 8) & 0xFF; 
ipParts[2] = (dest_ip >> 16) & 0xFF; 
ipParts[3] = (dest_ip >> 24) & 0xFF; 

发送部分:

// Build source sockaddr 
struct sockaddr_in src_addr; 
memset(&src_addr, 0, sizeof(struct sockaddr_in)); 
src_addr.sin_family = AF_INET; 

// Save IP into a char array 
char destIp[16]; 
memset(destIp, 0, sizeof(destIp)); 
sprintf(destIp, "%d.%d.%d.%d", ipParts[0], ipParts[1], ipParts[2], ipParts[3]); 
inet_aton(destIp, &(src_addr.sin_addr)); 

char cmbuf[CMSG_SPACE(sizeof(struct in_pktinfo))]; 

bzero(buffer, BUFLEN); 
int len = dp.getRaw(buffer); 

struct msghdr mh; 
memset(&mh, 0, sizeof(mh)); 

struct cmsghdr *cmsg_send; 
struct in_pktinfo *pktinfo; 

struct iovec iov[1]; 
iov[0].iov_base = buffer; 
iov[0].iov_len = BUFLEN; 

mh.msg_name = &cli_addr; // destination address of packet 
mh.msg_namelen = sizeof(cli_addr); 
mh.msg_control = cmbuf; 
mh.msg_controllen = sizeof(cmbuf); 
mh.msg_flags = 0; 
mh.msg_iov = iov; 
mh.msg_iovlen = 1; 

// after initializing msghdr & control data to CMSG_SPACE(sizeof(struct in_pktinfo)) 
cmsg_send = CMSG_FIRSTHDR(&mh); 
cmsg_send->cmsg_level = IPPROTO_IP; 
cmsg_send->cmsg_type = IP_PKTINFO; 
cmsg_send->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); 
pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg_send); 
pktinfo->ipi_ifindex = 0; 
pktinfo->ipi_spec_dst = src_addr.sin_addr; 

int rc = sendmsg(sock, &mh, 0); 
0

在进行Rx/Tx之前,典型的TCP/UDP套接字绑定在特定的IP /端口上。 尝试使用原始套接字进行处理。

其相当大的程序,请参考以下链接 http://sock-raw.org/papers/sock_raw

创建原始套接字 - 通过原始套接字 的Rx - 现在您将通过原始套接字收到完整的帧从L2 TX - 从L3头后发送修改相关字段

+0

你有描述这个或者一个小例子如何利用SOCK_RAW的链接吗?如果你不是IP和网络方面的专家,它看起来非常先进。 – user2215771

+0

请检查这个 –

1

您需要将bind()设置为本地IP地址,即您要使用的接口的IP地址。

阅读本指南,了解有关bind()

Beej's Guide To Networking#bind

+0

这就是问题所在。我不想绑定到特定的接口或IP地址。 – user2215771