#include #include #include #include #include #include #include #include #include static void die(const char *str) { fprintf(stderr, "%s\n", str); exit(1); } static int 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; 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 = 1; 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"); setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &n, sizeof(n)); 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)); } } return 0; } int main(int argc, char *argv[]) { int port = 9; const char *iface = NULL; if (argc > 1) iface = argv[1]; return run_proxy(iface, port); }