diff options
-rw-r--r-- | gre.c | 110 |
1 files changed, 98 insertions, 12 deletions
@@ -43,6 +43,7 @@ static int tun; static int sock; static struct sockaddr_storage remote; static size_t remote_len; +static int remote_any; static short type = IFF_TUN; static uint8_t mac[6]; static int foreground; @@ -59,6 +60,7 @@ static int setnonblock(int fd); static int runas(const char *user); static int daemonize(void); static int inet_addr_storage(const char *cp, struct sockaddr_storage *sp, size_t *sp_len); +static int is_any(const struct sockaddr_storage *ss); int main(int argc, char **argv) { @@ -101,15 +103,22 @@ int main(int argc, char **argv) } } - if ( (argc - optind) != 3) + int optnum = argc - optind; + + if (optnum < 2 || optnum > 3) { - printf("usage: %s [-n|--tun|-p|--tap] <tun> remote local\n", argv[0]); + printf("usage: %s [-n|--tun|-p|--tap] <tun> [remote] local\n", argv[0]); return EXIT_FAILURE; } const char *dev = argv[optind++]; - const char *remote_opt = argv[optind++]; - const char *local_opt = argv[optind++]; + const char *remote_opt = NULL; + const char *local_opt = NULL; + + if (optnum == 3) + remote_opt = argv[optind++]; + + local_opt = argv[optind++]; tun = tun_new(type, dev); if (tun < 0) @@ -139,12 +148,36 @@ int main(int argc, char **argv) return EXIT_FAILURE; } + if (!remote_opt) + { + if (local.ss_family == AF_INET) + remote_opt = "0.0.0.0"; + else + remote_opt = "::"; + } + if (inet_addr_storage(remote_opt, &remote, &remote_len)) { fprintf(stderr, "bad remote address\n"); return EXIT_FAILURE; } + remote_any = is_any(&remote); + if (remote_any) + { + if (type == IFF_TUN) + { + fprintf(stderr, "tun required specifying remote\n"); + return EXIT_FAILURE; + } + + if (local.ss_family != AF_INET) + { + fprintf(stderr, "IPv4 required for mGRE\n"); + return EXIT_FAILURE; + } + } + setnonblock(sock); setnonblock(tun); runas("nobody"); @@ -214,7 +247,7 @@ static void gre_cb(void) if (res < 0) { - printf("Failed GRE decode"); + printf("Failed GRE decode\n"); return; } @@ -318,6 +351,14 @@ static int gre_any(const uint8_t *buf, int n) static int tun_cb(void) { int n; + struct sockaddr_storage dest; + + if (!remote_any) + { + memcpy(&dest, &remote, sizeof(struct sockaddr_storage)); + } else { + memset(&dest, 0, sizeof(struct sockaddr_storage)); + } n = read(tun, buf, sizeof(buf)); if (n < 0) @@ -330,14 +371,36 @@ static int tun_cb(void) return 0; } uint16_t proto = ntohs(*(uint16_t *)(buf + 2)); - uint8_t *frame; + uint8_t *frame = buf; + + if (remote_any) + { + printf("%02x:%02x:%02x:%02x:%02x:%02x\n", + frame[4 + 0], + frame[4 + 1], + frame[4 + 2], + frame[4 + 3], + frame[4 + 4], + frame[4 + 5] + ); + + if (frame[4] != 0x2e || frame[5] != 0x2e) + { + printf("Bad magic number!\n"); + return 0; + } - if (type == IFF_TAP) + struct sockaddr_in *sin = (struct sockaddr_in *)&dest; + sin->sin_family = AF_INET; + memcpy(&sin->sin_addr.s_addr, frame + 4 + 2, 4); + + int offset = 2 + 6 + 6; + frame += offset; + n -= offset; + } + else if (type == IFF_TAP) { - frame = buf; *(uint16_t*)(frame + 2) = htons(ETH_P_TEB); - } else { - frame = buf; } frame[0] = 0; @@ -347,13 +410,20 @@ static int tun_cb(void) case ETHERTYPE_IPV6: break; case ETHERTYPE_ARP: - if (type == IFF_TAP) + if (type == IFF_TAP && !remote_any) break; return 0; default: return 0; } - sendto(sock, frame, n, 0, (struct sockaddr *)&remote, remote_len); + + if (is_any(&dest)) + { + printf("Remote unset!\n"); + return -1; + } + + sendto(sock, frame, n, 0, (struct sockaddr *)&dest, remote_len); return 0; } @@ -487,3 +557,19 @@ static int inet_addr_storage(const char *cp, struct sockaddr_storage *sp, size_t return 0; } + +static int is_any(const struct sockaddr_storage *ss) +{ + switch(ss->ss_family) { + case AF_INET: { + const struct sockaddr_in *sin = (const struct sockaddr_in*)ss; + return sin->sin_addr.s_addr == INADDR_ANY; + } + case AF_INET6: { + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6*)ss; + return !memcmp(&in6addr_any, sin6->sin6_addr.s6_addr, sizeof(struct in6_addr)); + } + default: + return -1; + } +} |