From 4969792065275ee0b997a4fa8841b00a93781a8e Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Sat, 9 Aug 2008 17:26:59 +0200 Subject: [PATCH] Initial hopefully working code. --- src/mctap.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- src/utils.h | 5 +++ 2 files changed, 127 insertions(+), 17 deletions(-) diff --git a/src/mctap.c b/src/mctap.c index 8125c41..472af01 100644 --- a/src/mctap.c +++ b/src/mctap.c @@ -6,15 +6,20 @@ #include #include #include +#include +#include +#include +#include +#include #include "utils.h" static void usage(FILE *out) { - fprintf(out, "usage: mctap [-h] MCASTGROUP PORT\n"); + fprintf(out, "usage: mctap [-h] [-D TAPNAME] MCASTGROUP PORT\n"); } -static char *formataddress(struct sockaddr *arg, socklen_t arglen) +static __attribute__ ((unused)) char *formataddress(struct sockaddr *arg, socklen_t arglen) { struct sockaddr_in *ipv4; struct sockaddr_in6 *ipv6; @@ -27,7 +32,7 @@ static char *formataddress(struct sockaddr *arg, socklen_t arglen) switch(arg->sa_family) { case AF_UNIX: - ret = strdup("Unix socket"); + ret = sstrdup("Unix socket"); break; case AF_INET: ipv4 = (struct sockaddr_in *)arg; @@ -74,38 +79,130 @@ static int mkmcastsk4(struct in_addr group, int port) return(fd); } -static void test(int fd) +static __attribute__ ((unused)) void test(int fd) { char buf[65536]; int i, ret; - struct sockaddr_storage nm; - socklen_t nmlen; + struct pollfd pfd; while(1) { - nmlen = sizeof(nm); - ret = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&nm, &nmlen); + pfd.fd = fd; + pfd.events = POLLIN; + ret = poll(&pfd, 1, -1); if(ret < 0) { - fprintf(stderr, "mctap: recvfrom: %s\n", strerror(ret)); + fprintf(stderr, "mctap: poll: %s\n", strerror(errno)); exit(1); } - printf("%s %i:\n", formataddress((struct sockaddr *)&nm, nmlen), ret); - for(i = 0; i < ret; i++) { - printf("%02x ", (unsigned char)buf[i]); - if(i % 20 == 0) - putchar(10); + if(pfd.revents) { + ret = read(fd, buf, sizeof(buf)); + if(ret < 0) { + fprintf(stderr, "mctap: read: %s\n", strerror(errno)); + exit(1); + } + for(i = 0; i < ret; i++) { + printf("%02x ", (unsigned char)buf[i]); + if(i % 20 == 19) + putchar(10); + } + putchar(10); } } } +static void bridge(int sock, int tap, struct sockaddr *dst, socklen_t dstlen) +{ + char buf[65536]; + int ret; + struct pollfd pfds[2]; + struct tun_pi pi; + + fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK); + fcntl(tap, F_SETFL, fcntl(tap, F_GETFL) | O_NONBLOCK); + while(1) { + pfds[0].fd = sock; + pfds[0].events = POLLIN; + pfds[1].fd = tap; + pfds[1].events = POLLIN; + ret = poll(pfds, 2, -1); + if(ret < 0) { + if(errno != EINTR) { + fprintf(stderr, "mctap: poll: %s\n", strerror(errno)); + exit(1); + } + continue; + } + if(pfds[0].revents) { + ret = read(sock, buf, sizeof(buf)); + if(ret < 0) { + if((errno != EINTR) && (errno != EAGAIN)) { + fprintf(stderr, "mctap: mcast packet: %s\n", strerror(errno)); + exit(1); + } + } else { + if(sizeof(buf) - ret < sizeof(pi)) { + /* Drop */ + } else { + memmove(buf + sizeof(pi), buf, ret); + pi.flags = 0; + pi.proto = 0; + memcpy(buf, &pi, sizeof(pi)); + write(tap, buf, ret); + } + } + } + if(pfds[1].revents) { + ret = read(tap, buf, sizeof(buf)); + if(ret < 0) { + if((errno != EINTR) && (errno != EAGAIN)) { + fprintf(stderr, "mctap: mcast packet: %s\n", strerror(errno)); + exit(1); + } + } else { + if(ret < sizeof(pi)) { + /* Drop */ + } else { + memcpy(&pi, buf, sizeof(pi)); + if(pi.flags & TUN_PKT_STRIP) { + /* Drop */ + } else { + sendto(sock, buf + sizeof(pi), ret - sizeof(pi), 0, dst, dstlen); + } + } + } + } + } +} + +static int maketap(char *name) +{ + int fd; + struct ifreq rb; + + if((fd = open("/dev/net/tun", O_RDWR)) < 0) + return(-1); + memset(&rb, 0, sizeof(rb)); + rb.ifr_flags = IFF_TAP; + strncpy(rb.ifr_name, name, IFNAMSIZ); + if(ioctl(fd, TUNSETIFF, &rb)) + return(-1); + return(fd); +} + int main(int argc, char **argv) { int c; - int sock; + int sock, tap; struct in_addr group; int port; + char *tapname; + struct sockaddr_in dst; - while((c = getopt(argc, argv, "h")) >= 0) { + tapname = "mctap"; + while((c = getopt(argc, argv, "hD:")) >= 0) { switch(c) { + case 'D': + tapname = optarg; + break; case 'h': usage(stdout); return(0); @@ -127,7 +224,15 @@ int main(int argc, char **argv) fprintf(stderr, "mctap: could not create multicast socket: %s\n", strerror(errno)); exit(1); } + if((tap = maketap(tapname)) < 0) { + fprintf(stderr, "mctap: could not create TAP device: %s\n", strerror(errno)); + exit(1); + } - test(sock); + memset(&dst, 0, sizeof(dst)); + dst.sin_family = AF_INET; + dst.sin_addr = group; + dst.sin_port = htons(port); + bridge(sock, tap, (struct sockaddr *)&dst, sizeof(dst)); return(0); } diff --git a/src/utils.h b/src/utils.h index 3a1c41a..8358244 100644 --- a/src/utils.h +++ b/src/utils.h @@ -67,6 +67,11 @@ struct buffer { size_t s, d; }; +struct intbuf { + int *b; + size_t s, d; +}; + struct charbuf { char *b; size_t s, d; -- 2.11.0