L4를 통해 VIP로 UDP 통신하기
에서 VIP 로 socket 을 binding 해서 응답을 보낼 수 있는데,이때 real ip로는 역시 통신을 할 수 없기때문에 유연성이 떨어지게 되는 문제가 있다.
결국, socket header를 조작해서
req. socket 의 수신 IP를 res. socket 의 송신 IP로 셋팅해서 해결한다.
일반적으로 사용되는 recvfrom() 대신,
IP_PKTINFO 를 통해 socket header 에서 수신 IP를 받아올 수 있는 recvfromto() 쯤을 만들어서 사용한다.
ssize_t recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen, struct sockaddr_in *to) { struct msghdr msg; struct iovec iov[1]; int n; struct cmsghdr *cmptr; union { struct cmsghdr cm; char control[CMSG_SPACE(sizeof(struct in_addr)) + CMSG_SPACE(sizeof(struct in_pktinfo))]; } control_un; int on = 1; struct in_pktinfo pktinfo; /* Try to enable getting the return address */ setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)); msg.msg_control = control_un.control; msg.msg_controllen = sizeof(control_un.control); msg.msg_flags = 0; msg.msg_name = from; msg.msg_namelen = *fromlen; iov[0].iov_base = buf; iov[0].iov_len = len; msg.msg_iov = iov; msg.msg_iovlen = 1; if ( (n = recvmsg(s, &msg, flags)) < 0 ) return n; /* Error */ *addrlen = msg.msg_namelen; if ( to ) { bzero(to, sizeof(struct sockaddr_in)); to->sin_family = AF_INET; if ( msg.msg_controllen < sizeof(struct cmsghdr) || (msg.msg_flags & MSG_CTRUNC) ) return n; /* No information available */ for ( cmptr = CMSG_FIRSTHDR(&msg) ; cmptr != NULL ; cmptr = CMSG_NXTHDR(&msg, cmptr) ) { if ( cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO ) { memcpy(&pktinfo, CMSG_DATA(cmptr), sizeof(struct in_pktinfo)); memcpy(&to->sin_addr, &pktinfo.ipi_addr, sizeof(struct in_addr)); } } } return n; }
그리고, 응답할때도 sendto() 대신,
socket header 에 송신 IP를 지정해서 보낼 수 있게, sendtofrom() 쯤을 만들어서 사용한다.
ssize_t sendtofrom(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen, struct sockaddr_in *from) { struct iovec iov = { buf, len }; struct { struct cmsghdr cm; struct in_pktinfo ipi; } cmsg = { .cm = { .cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo), .cmsg_level = SOL_IP, .cmsg_type = IP_PKTINFO, }, .ipi = { .ipi_ifindex = 0, .ipi_spec_dst = from->sin_addr, }, }; struct msghdr m = { .msg_name = to, .msg_namelen = tolen, .msg_iov = &iov, .msg_iovlen = 1, .msg_control = &cmsg, .msg_controllen = sizeof(cmsg), .msg_flags = 0, }; return sendmsg(s, &m, MSG_NOSIGNAL|MSG_DONTWAIT); }
자, 이제 RIP든 VIP든 어디로 오던지, 자유롭게 통신을 할 수 있게 된다.
ps. 그런데, 이런 건 기본 library 에 포함되야 하는 것 아닌가??? ㅡㅡ


