diff options
author | Natanael Copa <ncopa@alpinelinux.org> | 2013-05-09 20:57:11 +0200 |
---|---|---|
committer | Natanael Copa <ncopa@alpinelinux.org> | 2013-05-09 20:57:11 +0200 |
commit | 74fc0c9584b114decbe4c14bd6a8e220960794ca (patch) | |
tree | 0c9ec7a9a31aadc4715b130eddd19f52a17ce22b /wol-proxyd.c | |
download | wol-proxyd-74fc0c9584b114decbe4c14bd6a8e220960794ca.tar.bz2 wol-proxyd-74fc0c9584b114decbe4c14bd6a8e220960794ca.tar.xz |
initial commit
Diffstat (limited to 'wol-proxyd.c')
-rw-r--r-- | wol-proxyd.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/wol-proxyd.c b/wol-proxyd.c new file mode 100644 index 0000000..b36ce98 --- /dev/null +++ b/wol-proxyd.c @@ -0,0 +1,99 @@ +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <netdb.h> +#include <ifaddrs.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +static void die(const char *str) +{ + fprintf(stderr, "%s\n", str); + exit(1); +} + +static is_same_subnet(struct sockaddr_in *a, struct sockaddr_in *b, + struct sockaddr_in *mask) +{ + if (a->sin_family != b->sin_family) + return 0; + return ((a->sin_addr.s_addr & mask->sin_addr.s_addr) + == (b->sin_addr.s_addr & mask->sin_addr.s_addr)); +} + +static int get_bcast_addr(const char *iface, struct sockaddr_in *src, + struct sockaddr_in *bcast) +{ + struct ifaddrs *ifaddr, *ifa; + char host[NI_MAXHOST], bhost[NI_MAXHOST]; + int ret = 0; + + if (getifaddrs(&ifaddr) == -1) + die("getifaddrs"); + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL + || ifa->ifa_addr->sa_family != AF_INET + || (strcmp(iface, ifa->ifa_name) != 0)) + continue; + + /* dont forward broadcast from our own subnet(s) */ + if (is_same_subnet((struct sockaddr_in *)ifa->ifa_addr, src, + (struct sockaddr_in *)ifa->ifa_netmask)) + continue; + + memcpy(bcast, ifa->ifa_ifu.ifu_broadaddr, + sizeof(struct sockaddr_in)); + ret = sizeof(struct sockaddr_in); + break; + } + freeifaddrs(ifaddr); + return ret; +} + +static int run_proxy(const char *iface, int port) +{ + struct sockaddr_in src, dst; + char buf[256]; + int fd, n; + socklen_t addrlen; + + fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) + die("socket"); + + memset(&src, 0, sizeof(src)); + src.sin_family = AF_INET; + src.sin_port = htons(port); + src.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(fd, (struct sockaddr *)&src, sizeof(src)) < 0) + die("bind"); + + while (1) { + n = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&src, + &addrlen); + if (n < 0) + die("recvfrom"); + + if (get_bcast_addr(iface, &src, &dst)) { + dst.sin_port = htons(port); + sendto(fd, buf, n, 0, (struct sockaddr *) &dst, + sizeof(dst)); + } + } +} + +int main(int argc, char *argv[]) +{ + int c; + int port = 9; + const char *iface = NULL; + if (argc > 1) + iface = argv[1]; + run_proxy(iface, port); +} |