summaryrefslogtreecommitdiffstats
path: root/wol-proxyd.c
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2013-05-09 20:57:11 +0200
committerNatanael Copa <ncopa@alpinelinux.org>2013-05-09 20:57:11 +0200
commit74fc0c9584b114decbe4c14bd6a8e220960794ca (patch)
tree0c9ec7a9a31aadc4715b130eddd19f52a17ce22b /wol-proxyd.c
downloadwol-proxyd-74fc0c9584b114decbe4c14bd6a8e220960794ca.tar.bz2
wol-proxyd-74fc0c9584b114decbe4c14bd6a8e220960794ca.tar.xz
initial commit
Diffstat (limited to 'wol-proxyd.c')
-rw-r--r--wol-proxyd.c99
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);
+}