| diff -Naur ez-ipupdate-3.0.11b8.orig/ez-ipupdate.c ez-ipupdate-3.0.11b8/ez-ipupdate.c |
| --- ez-ipupdate-3.0.11b8.orig/ez-ipupdate.c 2011-01-23 19:35:10.885111914 +0100 |
| +++ ez-ipupdate-3.0.11b8/ez-ipupdate.c 2011-01-23 19:35:10.979110667 +0100 |
| @@ -172,6 +172,17 @@ |
| # ifdef HAVE_SYS_SOCKIO_H |
| # include <sys/sockio.h> |
| # endif |
| +# ifdef __linux__ |
| +/*# include <linux/if.h> */ |
| +# include <linux/netlink.h> |
| +# include <linux/rtnetlink.h> |
| +/* Under Linux, we reopen socket in get_if_addr() every time */ |
| +# define socketopen(sock) |
| +# define socketclose(sock) |
| +# else |
| +# define socketopen(sock) sock = socket(AF_INET, SOCK_STREAM, 0) |
| +# define socketclose(sock) close(sock) |
| +# endif |
| #endif |
| |
| #include <dprintf.h> |
| @@ -1605,6 +1616,114 @@ |
| int get_if_addr(int sock, char *name, struct sockaddr_in *sin) |
| { |
| #ifdef IF_LOOKUP |
| +#ifdef __linux__ |
| + struct { |
| + struct nlmsghdr nlmsg_info; |
| + struct ifaddrmsg ifaddrmsg_info; |
| + char buffer[2048]; |
| + } req; |
| + struct nlmsghdr *curr; |
| + int len; |
| + char buf[8192]; |
| + |
| + /* open a socket and bind it. |
| + Under non-linux, the socket can be kept open, but it seems under |
| + linux we cannot use the same socket for several requests reliable |
| + [although sometimes it works...] */ |
| + static struct sockaddr_nl local; |
| + sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); |
| + if(sock < 0) { |
| + perror("socket"); |
| + return -1; |
| + } |
| + local.nl_family = AF_NETLINK; |
| + local.nl_pad = 0; |
| + local.nl_pid = getpid(); |
| + local.nl_groups = 0; |
| + if(bind(sock, (struct sockaddr*) &local, sizeof(local)) < 0) { |
| + perror("bind"); |
| + close(sock); |
| + return -1; |
| + } |
| + |
| + memset(&req, 0, sizeof(req)); |
| + req.nlmsg_info.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); |
| + req.nlmsg_info.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; |
| + req.nlmsg_info.nlmsg_type = RTM_GETADDR; |
| + req.nlmsg_info.nlmsg_pid = getpid(); |
| + req.ifaddrmsg_info.ifa_family = AF_INET; |
| + if(send(sock, &req, req.nlmsg_info.nlmsg_len, 0) < 0) { |
| + perror("sendmsg(sock)"); |
| + close(sock); |
| + return -1; |
| + } |
| + |
| + len = recv(sock, buf, sizeof(buf), 0); |
| + close(sock); |
| + if(len < 0) { |
| + perror("recv"); |
| + return -1; |
| + } else if(len == 0) { |
| + dprintf((stderr, "No interfaces found")); |
| + return -1; |
| + } |
| + |
| + /* Initialize sin except for address */ |
| + bzero(sin, sizeof(struct sockaddr_in)); |
| + sin->sin_family = AF_INET; |
| + |
| + /* We take the last non-private IP with matching name */ |
| + int found = 0; |
| + curr = (struct nlmsghdr *) buf; |
| + for(; NLMSG_OK(curr, len); curr = NLMSG_NEXT(curr, len)) { |
| + struct ifaddrmsg *curraddr = (struct ifaddrmsg *) NLMSG_DATA(curr); |
| + struct rtattr *datalist = (struct rtattr *) IFA_RTA(curraddr); |
| + int datalen = IFA_PAYLOAD(curr); |
| + int mystat = 0; |
| + struct in_addr sin_addr; |
| + in_addr_t addr; |
| + for(; RTA_OK(datalist, datalen); datalist = RTA_NEXT(datalist, datalen)) { |
| + switch(datalist->rta_type) { |
| + case IFA_LABEL: |
| + if(strcmp((char *)RTA_DATA(datalist), name) != 0) |
| + mystat = -1; |
| + break; |
| + case IFA_LOCAL: |
| + addr = ((struct in_addr *)RTA_DATA(datalist))->s_addr; |
| + /* addr: 192.168.0.0/16 || 172.16.0.0/12 || 10.0.0.0/8 */ |
| + if(((addr & 0xFFFF) == 0xA8C0) |
| + || ((addr & 0xF0FF) == 0x10AC) |
| + || ((addr & 0xFF) == 0x0A)) { |
| + mystat = -1; |
| + } |
| + else { |
| + /* We must not store yet sin->sin_addr, since name might not match */ |
| + sin_addr = *((struct in_addr *)RTA_DATA(datalist)); |
| + mystat = 1; |
| + } |
| + break; |
| + default: |
| + break; |
| + } |
| + if(mystat < 0) |
| + break; |
| + } |
| + if(mystat > 0) { |
| + sin->sin_addr = sin_addr; |
| + found = 1; |
| + /* If you want to take the first non-private IP with matching name |
| + uncomment the next break command: |
| + break; */ |
| + } |
| + } |
| + if(found) { |
| + dprintf((stderr, "%s: %s\n", name, inet_ntoa(sin->sin_addr))); |
| + return 0; |
| + } |
| + dprintf((stderr, "%s: %s\n", name, "has no non-private address")); |
| + return -1; |
| +#else |
| +/* ifndef __linux__ */ |
| struct ifreq ifr; |
| |
| memset(&ifr, 0, sizeof(ifr)); |
| @@ -1638,7 +1757,10 @@ |
| return -1; |
| } |
| return -1; |
| +#endif |
| +/* endif __linux__ */ |
| #else |
| +/* ifndef IF_LOOKUP */ |
| return -1; |
| #endif |
| } |
| @@ -4490,7 +4612,7 @@ |
| #ifdef IF_LOOKUP |
| if(options & OPT_DAEMON) |
| { |
| - sock = socket(AF_INET, SOCK_STREAM, 0); |
| + socketopen(sock); |
| } |
| #endif |
| |
| @@ -4745,12 +4867,12 @@ |
| struct sockaddr_in sin; |
| int sock; |
| |
| - sock = socket(AF_INET, SOCK_STREAM, 0); |
| + socketopen(sock); |
| if(get_if_addr(sock, interface, &sin) != 0) |
| { |
| exit(1); |
| } |
| - close(sock); |
| + socketclose(sock); |
| snprintf(ipbuf, sizeof(ipbuf), "%s", inet_ntoa(sin.sin_addr)); |
| #else |
| fprintf(stderr, "interface lookup not enabled at compile time\n"); |
| @@ -4791,7 +4913,7 @@ |
| struct sockaddr_in sin; |
| int sock; |
| |
| - sock = socket(AF_INET, SOCK_STREAM, 0); |
| + socketopen(sock); |
| if(get_if_addr(sock, interface, &sin) == 0) |
| { |
| if(address) { free(address); } |
| @@ -4802,7 +4924,7 @@ |
| show_message("could not resolve ip address for %s.\n", interface); |
| exit(1); |
| } |
| - close(sock); |
| + socketclose(sock); |
| } |
| |
| for(i=0; i<ntrys; i++) |
| @@ -4846,12 +4968,12 @@ |
| struct sockaddr_in sin; |
| int sock; |
| |
| - sock = socket(AF_INET, SOCK_STREAM, 0); |
| + socketopen(sock); |
| if(get_if_addr(sock, interface, &sin) != 0) |
| { |
| exit(1); |
| } |
| - close(sock); |
| + socketclose(sock); |
| snprintf(ipbuf, sizeof(ipbuf), "%s", inet_ntoa(sin.sin_addr)); |
| #else |
| fprintf(stderr, "interface lookup not enabled at compile time\n"); |
| @@ -4878,7 +5000,7 @@ |
| } |
| |
| #ifdef IF_LOOKUP |
| - if(sock > 0) { close(sock); } |
| + if(sock > 0) { socketclose(sock); } |
| #endif |
| |
| if(address) { free(address); } |