5 #include <sys/socket.h>
6 #include <netinet/in.h>
10 #include <linux/if_tun.h>
12 #include <sys/ioctl.h>
20 static unsigned char macaddr[6];
22 static void usage(FILE *out)
24 fprintf(out, "usage: mctap [-hdpk] [-P PIDFILE] [-D TAPNAME] MCASTGROUP PORT\n");
27 static __attribute__ ((unused)) char *formataddress(struct sockaddr *arg, socklen_t arglen)
29 struct sockaddr_in *ipv4;
30 struct sockaddr_in6 *ipv6;
31 static char *ret = NULL;
37 switch(arg->sa_family)
40 ret = sstrdup("Unix socket");
43 ipv4 = (struct sockaddr_in *)arg;
44 if(inet_ntop(AF_INET, &ipv4->sin_addr, buf, sizeof(buf)) == NULL)
46 ret = sprintf2("%s:%i", buf, (int)ntohs(ipv4->sin_port));
49 ipv6 = (struct sockaddr_in6 *)arg;
50 if(inet_ntop(AF_INET6, &ipv6->sin6_addr, buf, sizeof(buf)) == NULL)
52 ret = sprintf2("[%s]:%i", buf, (int)ntohs(ipv6->sin6_port));
61 static int mkmcastsk4(struct in_addr group, int port)
65 struct sockaddr_in nm;
68 fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
70 if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &soval, sizeof(soval)))
72 memset(&nm, 0, sizeof(nm));
73 nm.sin_family = AF_INET;
74 nm.sin_port = htons(port);
75 if(bind(fd, (struct sockaddr *)&nm, sizeof(nm)))
77 memset(&mreq, 0, sizeof(mreq));
78 mreq.imr_multiaddr = group;
79 if(setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)))
82 if(setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &soval, sizeof(soval)))
87 static __attribute__ ((unused)) void test(int fd)
96 ret = poll(&pfd, 1, -1);
98 fprintf(stderr, "mctap: poll: %s\n", strerror(errno));
102 ret = read(fd, buf, sizeof(buf));
104 fprintf(stderr, "mctap: read: %s\n", strerror(errno));
107 for(i = 0; i < ret; i++) {
108 printf("%02x ", (unsigned char)buf[i]);
117 static void bridge(int sock, int tap, struct sockaddr *dst, socklen_t dstlen)
121 struct pollfd pfds[2];
124 fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
125 fcntl(tap, F_SETFL, fcntl(tap, F_GETFL) | O_NONBLOCK);
128 pfds[0].events = POLLIN;
130 pfds[1].events = POLLIN;
131 ret = poll(pfds, 2, -1);
134 syslog(LOG_ERR, "mctap: poll: %s", strerror(errno));
139 if(pfds[0].revents) {
140 ret = read(sock, buf, sizeof(buf));
142 if((errno != EINTR) && (errno != EAGAIN)) {
143 syslog(LOG_ERR, "mctap: mcast packet: %s", strerror(errno));
147 if(sizeof(buf) - ret < sizeof(pi)) {
149 } else if((ret < 12) || !memcmp(macaddr, buf + 6, 6)) {
150 /* Drop looped back */
152 memmove(buf + sizeof(pi), buf, ret);
155 memcpy(buf, &pi, sizeof(pi));
156 write(tap, buf, sizeof(pi) + ret);
160 if(pfds[1].revents) {
161 ret = read(tap, buf, sizeof(buf));
163 if((errno != EINTR) && (errno != EAGAIN)) {
164 syslog(LOG_ERR, "mctap: mcast packet: %s", strerror(errno));
168 if(ret < sizeof(pi)) {
171 memcpy(&pi, buf, sizeof(pi));
172 if(pi.flags & TUN_PKT_STRIP) {
175 sendto(sock, buf + sizeof(pi), ret - sizeof(pi), 0, dst, dstlen);
183 static int maketap(char *name)
188 if((fd = open("/dev/net/tun", O_RDWR)) < 0)
190 memset(&rb, 0, sizeof(rb));
191 rb.ifr_flags = IFF_TAP;
192 strncpy(rb.ifr_name, name, IFNAMSIZ);
193 if(ioctl(fd, TUNSETIFF, &rb))
195 if(ioctl(fd, SIOCGIFHWADDR, &rb))
197 memcpy(macaddr, rb.ifr_hwaddr.sa_data, 6);
201 static void sighand(int sig)
213 static void killrunning(char *pidfile)
218 if((pidfd = fopen(pidfile, "r")) == NULL) {
219 fprintf(stderr, "mctab -k: could not read PID file %s: %s\n", pidfile, strerror(errno));
222 fscanf(pidfd, "%i", &pid);
223 if(kill(pid, SIGTERM)) {
224 fprintf(stderr, "mctab -k: could not kill %i: %s\n", pid, strerror(errno));
230 int main(int argc, char **argv)
234 struct in_addr group;
238 int daemonize, killold;
239 struct sockaddr_in dst;
243 daemonize = killold = 0;
245 while((c = getopt(argc, argv, "hD:dpP:k")) >= 0) {
254 pidfile = (void *)-1;
262 pidfile = (void *)-1;
272 if(pidfile == (void *)-1)
273 pidfile = sprintf2("/var/run/mctap.%s.pid", tapname);
275 killrunning(pidfile);
278 if(argc - optind < 2) {
282 if(!inet_aton(argv[optind], &group)) {
283 fprintf(stderr, "mctap: invalid group address: %s\n", argv[optind]);
286 port = atoi(argv[optind + 1]);
287 if((sock = mkmcastsk4(group, port)) < 0) {
288 fprintf(stderr, "mctap: could not create multicast socket: %s\n", strerror(errno));
291 if((tap = maketap(tapname)) < 0) {
292 fprintf(stderr, "mctap: could not create TAP device: %s\n", strerror(errno));
295 openlog(sprintf2("mctap-%s", tapname), LOG_PID, LOG_DAEMON);
298 if((pidfile != NULL) && ((pidfd = fopen(pidfile, "w")) == NULL)) {
299 fprintf(stderr, "mctap: could not create PID file %s: %s\n", pidfile, strerror(errno));
305 fprintf(pidfd, "%i\n", getpid());
309 signal(SIGTERM, sighand);
310 signal(SIGINT, sighand);
311 signal(SIGHUP, sighand);
313 memset(&dst, 0, sizeof(dst));
314 dst.sin_family = AF_INET;
315 dst.sin_addr = group;
316 dst.sin_port = htons(port);
317 syslog(LOG_INFO, "bridge created with MAC %02x:%02x:%02x:%02x:%02x:%02x", macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]);
318 bridge(sock, tap, (struct sockaddr *)&dst, sizeof(dst));
319 syslog(LOG_INFO, "exiting");