summaryrefslogtreecommitdiffhomepage
path: root/gre.c
diff options
context:
space:
mode:
Diffstat (limited to 'gre.c')
-rw-r--r--gre.c398
1 files changed, 199 insertions, 199 deletions
diff --git a/gre.c b/gre.c
index 22ac0f6..eaef4eb 100644
--- a/gre.c
+++ b/gre.c
@@ -1,7 +1,7 @@
/*
* gre.c - userspace GRE tunnel
*
- * Copyright (C) 2015, Xiaoxiao <i@xiaoxiao.im>
+ * Copyright (C) 2015 - 2017, Xiaoxiao <i@pxx.io>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -50,231 +50,231 @@ static int daemonize(void);
int main(int argc, char **argv)
{
- fd_set readset;
-
- if (argc != 4)
- {
- printf("usage: %s <tun> remote local\n", argv[0]);
- return EXIT_FAILURE;
- }
-
- tun = tun_new(argv[1]);
- if (tun < 0)
- {
- printf("failed to init tun device\n");
- return EXIT_FAILURE;
- }
-
- sock = socket(AF_INET, SOCK_RAW, IPPROTO_GRE);
- if (sock < 0)
- {
- perror("socket");
- return EXIT_FAILURE;
- }
-
- struct sockaddr_in local;
- local.sin_family = AF_INET;
- local.sin_port = htons(IPPROTO_GRE);
- local.sin_addr.s_addr = inet_addr(argv[3]);
- if (local.sin_addr.s_addr == INADDR_NONE)
- {
- fprintf(stderr, "bad local address\n");
- return EXIT_FAILURE;
- }
- else
- {
- if (bind(sock, (struct sockaddr *)&local, sizeof(local)) != 0)
- {
- perror("bind");
- return EXIT_FAILURE;
- }
- }
-
- remote.sin_family = AF_INET;
- remote.sin_port = htons(IPPROTO_GRE);
- remote.sin_addr.s_addr = inet_addr(argv[2]);
- if (remote.sin_addr.s_addr == INADDR_NONE)
- {
- fprintf(stderr, "bad remote address\n");
- return EXIT_FAILURE;
- }
-
- setnonblock(sock);
- setnonblock(tun);
- runas("nobody");
- daemonize();
-
- int maxfd = (tun > sock ? tun : sock) + 1;
- while (1)
- {
- FD_ZERO(&readset);
- FD_SET(tun, &readset);
- FD_SET(sock, &readset);
-
- int r = select(maxfd, &readset, NULL, NULL, NULL);
- if (r < 0)
- {
- if (errno == EINTR)
- {
- continue;
- }
- else
- {
- perror("select");
- break;
- }
- }
-
- if (FD_ISSET(sock, &readset))
- {
- gre_cb();
- }
-
- if (FD_ISSET(tun, &readset))
- {
- tun_cb();
- }
- }
-
- return 0;
+ fd_set readset;
+
+ if (argc != 4)
+ {
+ printf("usage: %s <tun> remote local\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ tun = tun_new(argv[1]);
+ if (tun < 0)
+ {
+ printf("failed to init tun device\n");
+ return EXIT_FAILURE;
+ }
+
+ sock = socket(AF_INET, SOCK_RAW, IPPROTO_GRE);
+ if (sock < 0)
+ {
+ perror("socket");
+ return EXIT_FAILURE;
+ }
+
+ struct sockaddr_in local;
+ local.sin_family = AF_INET;
+ local.sin_port = htons(IPPROTO_GRE);
+ local.sin_addr.s_addr = inet_addr(argv[3]);
+ if (local.sin_addr.s_addr == INADDR_NONE)
+ {
+ fprintf(stderr, "bad local address\n");
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ if (bind(sock, (struct sockaddr *)&local, sizeof(local)) != 0)
+ {
+ perror("bind");
+ return EXIT_FAILURE;
+ }
+ }
+
+ remote.sin_family = AF_INET;
+ remote.sin_port = htons(IPPROTO_GRE);
+ remote.sin_addr.s_addr = inet_addr(argv[2]);
+ if (remote.sin_addr.s_addr == INADDR_NONE)
+ {
+ fprintf(stderr, "bad remote address\n");
+ return EXIT_FAILURE;
+ }
+
+ setnonblock(sock);
+ setnonblock(tun);
+ runas("nobody");
+ daemonize();
+
+ int maxfd = (tun > sock ? tun : sock) + 1;
+ while (1)
+ {
+ FD_ZERO(&readset);
+ FD_SET(tun, &readset);
+ FD_SET(sock, &readset);
+
+ int r = select(maxfd, &readset, NULL, NULL, NULL);
+ if (r < 0)
+ {
+ if (errno == EINTR)
+ {
+ continue;
+ }
+ else
+ {
+ perror("select");
+ break;
+ }
+ }
+
+ if (FD_ISSET(sock, &readset))
+ {
+ gre_cb();
+ }
+
+ if (FD_ISSET(tun, &readset))
+ {
+ tun_cb();
+ }
+ }
+
+ return 0;
}
static void gre_cb(void)
{
- int ihl; // IP header length
- int n;
-
- n = recv(sock, buf, sizeof(buf), 0);
- if (n < 0)
- {
- perror("recv");
- return;
- }
- ihl = 4 * (buf[0] & 0x0f);
- if (ihl > 60 || ihl < 20)
- {
- printf("IPv4 header too long\n");
- return;
- }
- // check source IPv4 address
- if (*(uint32_t *)(buf + 12) != remote.sin_addr.s_addr)
- {
- return;
- }
-
- // parse GRE header
- if (*(uint16_t *)(buf + ihl) != 0)
- {
- return;
- }
- uint16_t protocol = ntohs(*(uint16_t *)(buf + ihl + 2));
- if (protocol != 0x0800)
- {
- return;
- }
-
- write(tun, buf + ihl + 4, n - ihl - 4);
+ int ihl; // IP header length
+ int n;
+
+ n = recv(sock, buf, sizeof(buf), 0);
+ if (n < 0)
+ {
+ perror("recv");
+ return;
+ }
+ ihl = 4 * (buf[0] & 0x0f);
+ if (ihl > 60 || ihl < 20)
+ {
+ printf("IPv4 header too long\n");
+ return;
+ }
+ // check source IPv4 address
+ if (*(uint32_t *)(buf + 12) != remote.sin_addr.s_addr)
+ {
+ return;
+ }
+
+ // parse GRE header
+ if (*(uint16_t *)(buf + ihl) != 0)
+ {
+ return;
+ }
+ uint16_t protocol = ntohs(*(uint16_t *)(buf + ihl + 2));
+ if (protocol != 0x0800)
+ {
+ return;
+ }
+
+ write(tun, buf + ihl + 4, n - ihl - 4);
}
static void tun_cb(void)
{
- int n;
-
- n = read(tun, buf + 4, sizeof(buf) - 4);
- if (n < 0)
- {
- perror("read");
- return;
- }
- *(uint16_t *)(buf) = 0;
- *(uint16_t *)(buf + 2) = htons(0x0800);
- sendto(sock, buf, n + 4, 0, (struct sockaddr *)&remote, sizeof(struct sockaddr));
+ int n;
+
+ n = read(tun, buf + 4, sizeof(buf) - 4);
+ if (n < 0)
+ {
+ perror("read");
+ return;
+ }
+ *(uint16_t *)(buf) = 0;
+ *(uint16_t *)(buf + 2) = htons(0x0800);
+ sendto(sock, buf, n + 4, 0, (struct sockaddr *)&remote, sizeof(struct sockaddr));
}
static int tun_new(const char *dev)
{
- struct ifreq ifr;
- int fd, err;
-
- fd = open("/dev/net/tun", O_RDWR);
- if (fd < 0)
- {
- return -1;
- }
-
- bzero(&ifr, sizeof(struct ifreq));
-
- ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
- if (*dev != '\0')
- {
- strncpy(ifr.ifr_name, dev, IFNAMSIZ);
- }
-
- err = ioctl(fd, TUNSETIFF, (void *)&ifr);
- if (err < 0)
- {
- return err;
- }
- return fd;
+ struct ifreq ifr;
+ int fd, err;
+
+ fd = open("/dev/net/tun", O_RDWR);
+ if (fd < 0)
+ {
+ return -1;
+ }
+
+ bzero(&ifr, sizeof(struct ifreq));
+
+ ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+ if (*dev != '\0')
+ {
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ }
+
+ err = ioctl(fd, TUNSETIFF, (void *)&ifr);
+ if (err < 0)
+ {
+ return err;
+ }
+ return fd;
}
static int setnonblock(int fd)
{
- int flags;
- flags = fcntl(fd, F_GETFL, 0);
- if (flags == -1)
- {
- return -1;
- }
- if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK))
- {
- return -1;
- }
- return 0;
+ int flags;
+ flags = fcntl(fd, F_GETFL, 0);
+ if (flags == -1)
+ {
+ return -1;
+ }
+ if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK))
+ {
+ return -1;
+ }
+ return 0;
}
static int runas(const char *user)
{
- struct passwd *pw_ent = getpwnam(user);
-
- if (pw_ent != NULL)
- {
- if (setegid(pw_ent->pw_gid) != 0)
- {
- return -1;
- }
- if (seteuid(pw_ent->pw_uid) != 0)
- {
- return -1;
- }
- }
-
- return 0;
+ struct passwd *pw_ent = getpwnam(user);
+
+ if (pw_ent != NULL)
+ {
+ if (setegid(pw_ent->pw_gid) != 0)
+ {
+ return -1;
+ }
+ if (seteuid(pw_ent->pw_uid) != 0)
+ {
+ return -1;
+ }
+ }
+
+ return 0;
}
static int daemonize(void)
{
- pid_t pid;
+ pid_t pid;
- pid = fork();
- if (pid < 0)
- {
- perror("fork");
- return -1;
- }
+ pid = fork();
+ if (pid < 0)
+ {
+ perror("fork");
+ return -1;
+ }
- if (pid > 0)
- {
- exit(0);
- }
+ if (pid > 0)
+ {
+ exit(0);
+ }
- umask(0);
+ umask(0);
- if (setsid() < 0)
- {
- perror("setsid");
- return -1;
- }
+ if (setsid() < 0)
+ {
+ perror("setsid");
+ return -1;
+ }
- return 0;
+ return 0;
}