2013-10-08 2 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 주소를 스푸핑하고 싶습니까? – Salgar

+0

여러 개의 인터페이스가 있는데 스푸핑하고 싶지 않습니다. – user2215771

답변

0

내 문제를 해결 한 좋은 방식으로 솔루션을 게시해야합니다! SOCK_RAW를 사용하지 않았고 로컬 IP 나 그와 같은 인터페이스에 내 인터페이스를 바인드하지도 않았습니다. 이것은 구글과 일부 stackoverflow에 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

일반적인 TCP/UDP 소켓은 Rx/Tx를 수행하기 전에 특정 IP/포트에 바인딩됩니다. 원시 소켓을 사용해보십시오. 원시 소켓을 통해 수신하면 원시 소켓을 통해 L2에서 송신을 전체 프레임을받을 것이다 - 지금 - -

는 오히려 큰 코드, http://sock-raw.org/papers/sock_raw

원시 소켓을 만들려면 다음 링크를 참조하시기 바랍니다 후 L3 헤더에서 전송 관련 필드 수정

+0

SOCK_RAW를 활용하는 방법에 대한 간단한 설명이 나와있는 링크가 있습니까? IP 및 네트워킹 전문가가 아닌 경우 정말 발전된 모양입니다. – user2215771

+0

이것을 확인하십시오 –

1

사용하려는 인터페이스의 IP 인 로컬 IP 주소에 bind()이 필요합니다.

이 가이드를 읽기에 대한 bind()

Beej's Guide To Networking#bind

+0

그건 문제의 종류입니다.특정 인터페이스 나 IP 주소에 바인딩하고 싶지 않습니다. – user2215771