2013-10-08 126 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