1// A broadcast packet repeater. This packet repeater (currently designed for 2// udp packets) will listen for broadcast packets. 3// When it receives the packets, it will then re-broadcast the packet. 4// 5// Written by TheyCallMeLuc(at)yahoo.com.au 6// I accept no responsiblity for the function of this program if you 7// choose to use it. 8// Modified for Poptop by Richard de Vroede <r.devroede@linvision.com> 9// Ditto on the no responsibility. 10// 11// Rewritten by Norbert van Bolhuis <norbert@vanbolhuis.demon.nl> bcrelay (v1.0+) 12// now supports/does: 13// 1) Relaying from PPP (VPN tunnel) interfaces, hereby creating a virtual 14// LAN (w.r.t. UDP broadcasts) for VPN clients and ethernet PCs 15// belonging/matching the subnet portion of the VPN IP addresses. 16// So now broadcasting to/from all systems of the VPN has been implemented. 17// Note that bcrelay v0.5 only relayed from LAN to VPN clients. 18// It doesn't matter whether the systems on the VPN are on the LAN of the 19// VPN server or have a VPN/PPTP connection (over the internet) to the VPN 20// server. Broadcasts will always be relayed to/from all given interfaces. And 21// as long as the subnet portion of the IP addresses of the systems on the VPN 22// matches, the VPN server will be able to route properly. This means all 23// networking applications/games that rely on a UDP broadcast from one or 24// more PPP (VPN tunnel) interfaces will now see eachother and work over 25// the VPN. 26// Note that it depends on the networking application/game and whoever 27// acts as application/game server/host who is sending (UPD) broadcasts 28// and who is listening. 29// 2) UDP broadcasts received on a PPP interface (VPN tunnel) sometimes 30// don't carry the VPN IP address which pptpd provisioned. I've seen 31// this happening on a WinXP SP1 box, especially when the application 32// responsible for the UDP broadcasts isn't aware of the PPP interface. 33// In this case it just uses the LAN IP src address for the IP src 34// address of the inner (GRE encapsulated) IP packet. This breaks 35// the "virtual LAN" and therefore bcrelay, as of this version, changes 36// the src IP address to the VPN IP address (which pptpd provisioned) 37// before relaying. 38// 3) To avoid a UDP broadcast loop, bcrelay changes the IP TTL and the 39// UDP checksum (to 1 and 0 respectively) of the UDP broadcasts it relays. 40// No relaying will be done for UDP broadcasts with IP TTL=1 and UDP 41// checksum=0. Could also (mis)use IP identification for this, but IP TTL 42// and UDP chksum combination is expected to work fine. 43// 4) bcrelay v0.5 forgot to update IP/UDP checksum when it changed the 44// dest. IP address (e.g. from 192.168.1.255 to 255.255.255.255). 45// Of course as of this version bcrelay always updates the IP/UDP 46// checksum since the IP TTL and src IP address will change also. 47// 5) Enhanced the (syslog) debugging capabilities. By default bcrelay will 48// show what it is doing. Bcrelay will syslog the IP interfaces it tries 49// to read/relay UDP broadcasts from/to. These interfaces are called 50// the 'active interfaces', bcrelay will syslog the initial set of active 51// interfaces and whenever the set changes. Currently there is no difference 52// between an incoming interface (given with -i) and an outgoing interface 53// (given with -o), so bcrelay won't show this attribute. Also, bcrelay will 54// syslog a successfully relayed UDP broadcast, including the UDP port numbers, 55// the incoming interface and the interface(s) to which it was successfully 56// relayed. The (new) -n option allows to suppress syslog tracing. 57// If -n is given, bcrelay shows/syslogs nothing, except fatal error 58// messages. 59// 60// This software is completely free. You can use and/or modify this 61// software to your hearts content. You are free to redistribute it as 62// long as it is accompanied with the source and my credit is included. 63 64#ifdef HAVE_CONFIG_H 65#include "config.h" 66#endif 67 68#ifdef __linux__ 69#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */ 70#endif 71 72#ifdef __svr4__ 73#define __EXTENSIONS__ 1 /* strdup() prototype */ 74#endif 75 76#ifdef __sgi__ 77#define _XOPEN_SOURCE 500 /* strdup() prototype */ 78#endif 79 80#include <fcntl.h> 81#include <stdio.h> 82#include <stdlib.h> 83#include <netdb.h> 84#include <unistd.h> 85#include <string.h> 86#include <libgen.h> 87#include <time.h> 88#include <sys/time.h> 89#include <regex.h> 90#include <net/if.h> 91#include <sys/ioctl.h> 92#include <sys/socket.h> 93#include <sys/types.h> 94#include <netinet/in.h> 95#include <netpacket/packet.h> 96#include <net/ethernet.h> 97#include <netinet/ip.h> 98#include <netinet/udp.h> 99#include <netinet/tcp.h> 100#include <dirent.h> 101 102#ifdef __linux__ 103#include <linux/filter.h> 104#endif 105 106#include "defaults.h" 107#include "our_syslog.h" 108#include "our_getopt.h" 109 110//#define VERSION "1.0" 111 112/* uncomment if you compile this without poptop's configure script */ 113//#define HAVE_FORK 114 115/* 116 * Value-return macros to fields in the IP PDU header 117 */ 118#define IP_IPPDU_IHL(ippdu) (*(unsigned char *)(ippdu) & 0x0F) 119#define IP_IPPDU_PROTO(ippdu) (*((unsigned char *)(ippdu) + 9) & 0xFF) 120 121/* 122 * Pointer macros to fields in the IP PDU header 123 */ 124#define IP_IPPDU_CHECKSUM_MSB_PTR(ippdu) ((unsigned char *)(ippdu) + 10 ) 125#define IP_IPPDU_CHECKSUM_LSB_PTR(ippdu) ((unsigned char *)(ippdu) + 11 ) 126 127/* 128 * Pointer macros to fields in the UDP PDU header 129 */ 130#define IP_UDPPDU_CHECKSUM_MSB_PTR(udppdu) ((unsigned char *)(udppdu) + 6 ) 131#define IP_UDPPDU_CHECKSUM_LSB_PTR(udppdu) ((unsigned char *)(udppdu) + 7 ) 132 133#define MAXIF 255 // Maximum interfaces to use 134#define MAX_SELECT_WAIT 3 // Maximum time (in secs) to wait for input on the socket/interfaces 135 // A time-out triggers the discovery of new interfaces. 136#define MAX_NODISCOVER_IFS 12 // Maximum time (in secs) to elaps before a discovery of new 137 // interfaces is triggered. Only when a packet keeps coming in 138 // (this prevents a select time-out) a variable initialized with 139 // this #define becomes 0 and a rediscovery of the interfaces is 140 // triggered. 141#define MAX_IFLOGTOSTR 16 142 143/* Local function prototypes */ 144static void showusage(char *prog); 145static void showversion(); 146#ifndef HAVE_DAEMON 147static void my_daemon(int argc, char **argv); 148#endif 149static void mainloop(int argc, char **argv); 150 151struct packet { 152 struct iphdr ip; 153 struct udphdr udp; 154 char data[ETHERMTU]; 155}; 156 157 158/* 159 * struct that keeps track of the interfaces of the system 160 * selected upon usage by bcrelay (with -i and -o option). 161 * An array of this struct is returned by discoverActiveInterfaces. 162 * This array is reset (filled from scratch) each time 163 * discoverActiveInterfaces is called. 164 */ 165struct iflist { 166//Fix 3mar2003 167 //char index; 168 int index; 169 u_int32_t bcast; 170 char ifname[16+1]; 171 unsigned long ifaddr; 172 unsigned long ifdstaddr; 173 unsigned long flags1; 174}; 175 176#define IFLIST_FLAGS1_IF_IS_ETH 0x00000001 177#define IFLIST_FLAGS1_IF_IS_PPP 0x00000002 178#define IFLIST_FLAGS1_IF_IS_UNKNOWN 0x00000004 179#define IFLIST_FLAGS1_CHANGED_INNER_SADDR 0x00010000 180 181 182/* 183 * struct that keeps track of the socket fd's for every interface 184 * that is in use (and thus present in iflist). 185 * Two permanent arrays of this struct are used, one for the 186 * previous/old list and one for the current list. 187 */ 188struct ifsnr { 189 int sock_nr; 190 int ifindex; 191}; 192 193static void copy_ifsnr(struct ifsnr *from, struct ifsnr *to); 194static int find_sock_nr(struct ifsnr *l, int ifidx); 195struct iflist *discoverActiveInterfaces(void); 196void ip_update_checksum(unsigned char *ippdu); 197static char *IpProtToString( unsigned char prot ); 198static char *iflistToString( struct iflist *ifp ); 199static char *iflistLogIToString( struct iflist *ifp, int idx, struct ifsnr *ifnr ); 200static char *iflistLogRToString( struct iflist *ifp, int idx, struct ifsnr *ifnr ); 201static void bind_to_iface(int fd, int ifindex); 202 203/* 204 * This global variable determines whether NVBCR_PRINTF actually 205 * displays something. While developping v1.0, NVBCR_PRINTF were 206 * printf and a lot of tracing/logging/debugging was done with these. 207 * Of course, by default these 'info' messages have been turned off 208 * now. Enable by setting variable to 1. Note that output will only 209 * appear in non-daemon mode (see also NVBCR_PRINTF). 210 */ 211static int do_org_info_printfs = 0; 212 213static int vnologging = 0; 214static int vdaemon = 0; 215 216#define NVBCR_PRINTF( args ) \ 217 if ((vdaemon == 0) && (do_org_info_printfs == 1)) printf args 218 219static char interfaces[32]; 220static char log_interfaces[MAX_IFLOGTOSTR*MAXIF]; 221static char log_relayed[(MAX_IFLOGTOSTR-1)*MAXIF+81]; 222static char *ipsec = ""; 223 224static void showusage(char *prog) 225{ 226 printf("\nBCrelay v%s\n\n", VERSION); 227 printf("A broadcast packet repeater. This packet repeater (currently designed for udp packets) will listen\n"); 228 printf(" for broadcast packets. When it receives the packets, it will then re-broadcast the packet.\n\n"); 229 printf("Usage: %s [options], where options are:\n\n", prog); 230 printf(" [-d] [--daemon] Run as daemon.\n"); 231 printf(" [-h] [--help] Displays this help message.\n"); 232 printf(" [-i] [--incoming <ifin>] Defines from which interface broadcasts will be relayed.\n"); 233 printf(" [-n] [--nolog] No logging/tracing to /var/log/messages.\n"); 234 printf(" [-o] [--outgoing <ifout>] Defines to which interface broadcasts will be relayed.\n"); 235 printf(" [-s] [--ipsec <arg>] Defines an ipsec tunnel to be relayed to.\n"); 236 printf(" Since ipsec tunnels terminate on the same interface, we need to define the broadcast\n"); 237 printf(" address of the other end-point of the tunnel. This is done as ipsec0:x.x.x.255\n"); 238 printf(" [-v] [--version] Displays the BCrelay version number.\n"); 239 printf("\nLog messages and debugging go to syslog as DAEMON.\n\n"); 240 printf("\nInterfaces can be specified as regexpressions, ie. ppp[0-9]+\n\n"); 241} 242 243static void showversion() 244{ 245 printf("BCrelay v%s\n", VERSION); 246} 247 248#ifndef HAVE_DAEMON 249static void my_daemon(int argc, char **argv) 250{ 251 pid_t pid; 252#ifndef BCRELAY_BIN 253/* Need a smart way to locate the binary -rdv */ 254#define BCRELAY_BIN argv[0] 255#endif 256#ifndef HAVE_FORK 257 /* need to use vfork - eg, uClinux */ 258 char **new_argv; 259 extern char **environ; 260 int minusd=0; 261 int i; 262 int fdr; 263 264 /* Strip -d option */ 265 new_argv = malloc((argc) * sizeof(char **)); 266 fdr = open("/dev/null", O_RDONLY); 267 new_argv[0] = BCRELAY_BIN; 268 for (i = 1; argv[i] != NULL; i++) { 269 if (fdr != 0) { dup2(fdr, 0); close(fdr); } 270 if ( (strcmp(argv[i],"-d")) == 0 ) { 271 minusd=1; 272 } 273 if (minusd) { 274 new_argv[i] = argv[i+1]; 275 } else { 276 new_argv[i] = argv[i]; 277 } 278 } 279 syslog(LOG_DEBUG, "Option parse OK, re-execing as daemon"); 280 fflush(stderr); 281 if ((pid = vfork()) == 0) { 282 if (setsid() < 0) { /* shouldn't fail */ 283 syslog(LOG_ERR, "Setsid failed!"); 284 _exit(1); 285 } 286 chdir("/"); 287 umask(0); 288 /* execve only returns on an error */ 289 execve(BCRELAY_BIN, new_argv, environ); 290 exit(1); 291 } else if (pid > 0) { 292 syslog(LOG_DEBUG, "Success re-execing as daemon!"); 293 exit(0); 294 } else { 295 syslog(LOG_ERR, "Error vforking"); 296 exit(1); 297 } 298#else 299 pid=fork(); 300 if (pid<0) { syslog(LOG_ERR, "Error forking"); _exit(1); } 301 if (pid>0) { syslog(LOG_DEBUG, "Parent exits"); _exit(0); } 302 if (pid==0) { syslog(LOG_DEBUG, "Running as child"); } 303 /* child (daemon) continues */ 304 if (setsid() < 0) { /* shouldn't fail */ 305 syslog(LOG_ERR, "Setsid failed!"); 306 _exit(1); 307 } 308 chdir("/"); 309#endif 310} 311#endif 312 313int main(int argc, char **argv) { 314 regex_t preg; 315 /* command line options */ 316 int c; 317 char *ifout = ""; 318 char *ifin = ""; 319 320#ifndef BCRELAY 321 fprintf(stderr, 322 "bcrelay: pptpd was compiled without support for bcrelay, exiting.\n" 323 " run configure --with-bcrelay, make, and install.\n"); 324 exit(1); 325#endif 326 327 /* open a connection to the syslog daemon */ 328 openlog("bcrelay", LOG_PID, PPTP_FACILITY); 329 330 while (1) { 331 int option_index = 0; 332 333 static struct option long_options[] = 334 { 335 {"nolog", 0, 0, 0}, 336 {"daemon", 0, 0, 0}, 337 {"help", 0, 0, 0}, 338 {"incoming", 1, 0, 0}, 339 {"outgoing", 1, 0, 0}, 340 {"ipsec", 1, 0, 0}, 341 {"version", 0, 0, 0}, 342 {0, 0, 0, 0} 343 }; 344 345 c = getopt_long(argc, argv, "ndhi:o:s:v", long_options, &option_index); 346 if (c == -1) 347 break; 348 /* convert long options to short form */ 349 if (c == 0) 350 c = "ndhiosv"[option_index]; 351 switch (c) { 352 case 'n': 353 vnologging = 1; 354 break; 355 case 'd': 356 vdaemon = 1; 357 break; 358 case 'h': 359 showusage(argv[0]); 360 return 0; 361 case 'i': 362 ifin = strdup(optarg); 363 break; 364 case 'o': 365 ifout = strdup(optarg); 366 break; 367 case 's': 368 ipsec = strdup(optarg); 369 // Validate the ipsec parameters 370 regcomp(&preg, "ipsec[0-9]+:[0-9]+.[0-9]+.[0-9]+.255", REG_EXTENDED); 371 if (regexec(&preg, ipsec, 0, NULL, 0)) { 372 syslog(LOG_INFO,"Bad syntax: %s", ipsec); 373 fprintf(stderr, "\nBad syntax: %s\n", ipsec); 374 showusage(argv[0]); 375 return 0; 376 } else { 377 regfree(&preg); 378 break; 379 } 380 case 'v': 381 showversion(); 382 return 0; 383 default: 384 showusage(argv[0]); 385 return 1; 386 } 387 } 388 if (!(ifin && *ifin)) { 389 syslog(LOG_INFO,"Incoming interface required!"); 390 showusage(argv[0]); 391 _exit(1); 392 } 393 if (!(ifout && *ifout) && !(ipsec && *ipsec)) { 394 syslog(LOG_INFO,"Listen-mode or outgoing or IPsec interface required!"); 395 showusage(argv[0]); 396 _exit(1); 397 } else { 398 sprintf(interfaces,"%s|%s", ifin, ifout); 399 } 400 401 // If specified, become Daemon. 402 if (vdaemon) { 403#if HAVE_DAEMON 404 closelog(); 405 freopen("/dev/null", "r", stdin); 406 /* set noclose, we want stdout/stderr still attached if we can */ 407 daemon(0, 1); 408 /* returns to child only */ 409 /* pid will have changed */ 410 openlog("bcrelay", LOG_PID, PPTP_FACILITY); 411#else /* !HAVE_DAEMON */ 412 my_daemon(argc, argv); 413 /* returns to child if !HAVE_FORK 414 * never returns if HAVE_FORK (re-execs without -d) 415 */ 416#endif 417 } else { 418 syslog(LOG_INFO, "Running as child\n"); 419 } 420 mainloop(argc,argv); 421 _exit(0); 422} 423 424static void mainloop(int argc, char **argv) 425{ 426 socklen_t salen = sizeof(struct sockaddr_ll); 427 int i, rcg, j, no_discifs_cntr, ifs_change; 428 int logstr_cntr; 429 struct iflist *iflist = NULL; // Initialised after the 1st packet 430 struct sockaddr_ll sa; 431 struct packet *ipp_p; 432 char *udppdu; // FIXME: warning: pointer targets in assignment differ in signedness 433 fd_set sock_set; 434 struct timeval time_2_wait; 435 static struct ifsnr old_ifsnr[MAXIF+1]; // Old iflist to socket fd's mapping list 436 static struct ifsnr cur_ifsnr[MAXIF+1]; // Current iflist to socket fd's mapping list 437 unsigned char buf[1518]; 438 char *logstr = ""; 439 440 no_discifs_cntr = MAX_NODISCOVER_IFS; 441 ifs_change = 0; 442 443 /* 444 * Discover interfaces (initial set) and create a dedicated socket bound to the interface 445 */ 446 memset(old_ifsnr, -1, sizeof(old_ifsnr)); 447 memset(cur_ifsnr, -1, sizeof(cur_ifsnr)); 448 iflist = discoverActiveInterfaces(); 449 for (i=0; iflist[i].index; ++i) { 450 if ((cur_ifsnr[i].sock_nr = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { 451 syslog(LOG_ERR, "mainloop: Error, socket error! (rv=%d, errno=%d)", cur_ifsnr[i].sock_nr, errno); 452 exit(1); 453 } 454 bind_to_iface(cur_ifsnr[i].sock_nr, iflist[i].index); 455 cur_ifsnr[i].ifindex = iflist[i].index; 456 } 457 NVBCR_PRINTF(("Displaying INITIAL active interfaces..\n")); 458 if (vnologging == 0) { 459 logstr = log_interfaces; 460 logstr_cntr = sprintf(logstr, "Initial active interfaces: "); 461 logstr += logstr_cntr; 462 } 463 for (i = 0; iflist[i].index; i++) 464 { 465 NVBCR_PRINTF(("\t\tactive interface number: %d, if=(%s), sock_nr=%d\n", i, iflistToString(&(iflist[i])), cur_ifsnr[i].sock_nr)); 466 if (vnologging == 0) { 467 logstr_cntr = sprintf(logstr, "%s ", iflistLogIToString(&(iflist[i]), i, &(cur_ifsnr[i]))); 468 logstr += logstr_cntr; 469 } 470 } 471 if (vnologging == 0) syslog(LOG_INFO, "%s", log_interfaces); 472 473 // Main loop 474 while (1) 475 { 476 477 /* 478 * Check all (interface) sockets for incoming packets 479 */ 480 FD_ZERO(&sock_set); 481 for (i=0; iflist[i].index; ++i) 482 { 483 if (cur_ifsnr[i].sock_nr >= 0) { 484 FD_SET(cur_ifsnr[i].sock_nr, &sock_set); 485 } 486 } 487 488 /* 489 * Don't wait more than MAX_SELECT_WAIT seconds 490 */ 491 time_2_wait.tv_sec = MAX_SELECT_WAIT; 492 time_2_wait.tv_usec = 0L; 493 494 /* select on sockets */ 495 rcg = select(MAXIF, &sock_set, (fd_set *) NULL,(fd_set *) NULL, &time_2_wait); 496 497 if (rcg < 0) 498 { 499 syslog(LOG_ERR, "Error, select error! (rv=%d, errno=%d)", rcg, errno); 500 exit(1); 501 } 502 503 if (rcg == 0) 504 { 505 /* TimeOut, rediscover interfaces */ 506 NVBCR_PRINTF(("Select timeout, rediscover interfaces\n")); 507 copy_ifsnr(cur_ifsnr, old_ifsnr); 508 memset(cur_ifsnr, -1, sizeof(cur_ifsnr)); 509 iflist = discoverActiveInterfaces(); 510 /* 511 * Build new cur_ifsnr list. 512 * Make iflist[i] correspond with cur_ifsnr[i], so iflist[i].index == cur_ifsnr[i].ifindex 513 * The old list (old_ifsnr) is used to compare. 514 */ 515 for (i=0; iflist[i].index; ++i) { 516 /* check to see if it is a NEW interface */ 517 int fsnr = find_sock_nr(old_ifsnr, iflist[i].index); 518 if (fsnr == -1) { 519 /* found new interface, open dedicated socket and bind it to the interface */ 520 if ((cur_ifsnr[i].sock_nr = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { 521 syslog(LOG_ERR, "mainloop: Error, socket error! (rv=%d, errno=%d)", cur_ifsnr[i].sock_nr, errno); 522 exit(1); 523 } 524 bind_to_iface(cur_ifsnr[i].sock_nr, iflist[i].index); 525 ifs_change = 1; 526 } 527 else 528 { 529 /* 530 * not a new interface, socket already openen, interface already 531 * bound. Update cur_ifsnr. 532 */ 533 cur_ifsnr[i].sock_nr = fsnr; 534 } 535 cur_ifsnr[i].ifindex = iflist[i].index; 536 } 537 /* Close disappeared interfaces */ 538 for (i=0; i<MAXIF; ++i) 539 { 540 if ((old_ifsnr[i].sock_nr != -1) && (old_ifsnr[i].ifindex != -1) && 541 (find_sock_nr(cur_ifsnr, old_ifsnr[i].ifindex) == -1)) { 542 NVBCR_PRINTF(("Closing an interface (it disappeared), namely: (s_nr=%d, ifidx=%d)\n", old_ifsnr[i].sock_nr, old_ifsnr[i].ifindex)); 543 close(old_ifsnr[i].sock_nr); 544 old_ifsnr[i].sock_nr = -1; 545 old_ifsnr[i].ifindex = -1; 546 ifs_change = 1; 547 } 548 } 549 if (ifs_change == 1) 550 { 551 NVBCR_PRINTF(("Active interface set changed --> displaying current active interfaces..\n")); 552 if (vnologging == 0) { 553 logstr = log_interfaces; 554 logstr_cntr = sprintf(logstr, "Active interface set changed to: "); 555 logstr += logstr_cntr; 556 } 557 for (i = 0; iflist[i].index; i++) 558 { 559 NVBCR_PRINTF(("\t\tactive interface number: %d, if=(%s), sock_nr=%d\n", i, iflistToString(&(iflist[i])), cur_ifsnr[i].sock_nr)); 560 if (vnologging == 0) { 561 logstr_cntr = sprintf(logstr, "%s ", iflistLogIToString(&(iflist[i]), i, &(cur_ifsnr[i]))); 562 logstr += logstr_cntr; 563 } 564 } 565 if (vnologging == 0) syslog(LOG_INFO, "%s", log_interfaces); 566 ifs_change = 0; 567 } 568 continue; 569 } 570 571 if (rcg > 0) 572 { 573 /* rcg interfaces have pending input */ 574 for (i=0; ((iflist[i].index != 0) && (rcg > 0)); ++i) 575 { 576 if ((cur_ifsnr[i].sock_nr != -1) && (FD_ISSET(cur_ifsnr[i].sock_nr,&sock_set))) 577 { 578 /* Valid socket number and pending input, let's read */ 579 int rlen = read(cur_ifsnr[i].sock_nr, buf, sizeof(buf)); 580 ipp_p = (struct packet *)&(buf[0]); 581 NVBCR_PRINTF(("IP_Packet=(tot_len=%d, id=%02x%02x, ttl=%d, prot=%s, src_ip=%d.%d.%d.%d, dst_ip=%d.%d.%d.%d) (on if: %d/%d) ", ntohs(ipp_p->ip.tot_len), (ntohs(ipp_p->ip.id))>>8, (ntohs(ipp_p->ip.id))&0x00ff, ipp_p->ip.ttl, IpProtToString(ipp_p->ip.protocol), (ntohl(ipp_p->ip.saddr))>>24, ((ntohl(ipp_p->ip.saddr))&0x00ff0000)>>16, ((ntohl(ipp_p->ip.saddr))&0x0000ff00)>>8, (ntohl(ipp_p->ip.saddr))&0x000000ff, (ntohl(ipp_p->ip.daddr))>>24, ((ntohl(ipp_p->ip.daddr))&0x00ff0000)>>16, ((ntohl(ipp_p->ip.daddr))&0x0000ff00)>>8, (ntohl(ipp_p->ip.daddr))&0x000000ff, i, iflist[i].index)); 582 rcg -= 1; 583 584 if ( (ipp_p->ip.protocol == IPPROTO_UDP) && 585 (((ntohl(ipp_p->ip.daddr)) & 0x000000ff) == 0x000000ff) && 586 (ipp_p->ip.ttl != 1) && 587 (!((*IP_UDPPDU_CHECKSUM_MSB_PTR((unsigned char *)ipp_p+(4*ipp_p->ip.ihl)) == 0) && 588 (*IP_UDPPDU_CHECKSUM_LSB_PTR((unsigned char *)ipp_p+(4*ipp_p->ip.ihl)) == 0))) ) 589 { 590 int nrsent; 591 int ifindex_to_exclude = iflist[i].index; 592 593 NVBCR_PRINTF(("is an UDP BROADCAST (dstPort=%d, srcPort=%d) (with TTL!=1 and UDP_CHKSUM!=0)\n\n", 594 ntohs(ipp_p->udp.dest), ntohs(ipp_p->udp.source))); 595 if (vnologging == 0) { 596 logstr = log_relayed; 597 logstr_cntr = sprintf(logstr, "UDP_BroadCast(sp=%d,dp=%d) from: %s relayed to: ", ntohs(ipp_p->udp.source), 598 ntohs(ipp_p->udp.dest), iflistLogRToString(&(iflist[i]), i, &(cur_ifsnr[i]))); 599 logstr += logstr_cntr; 600 } 601 602 /* going to relay a broadcast packet on all the other interfaces */ 603 for (j=0; iflist[j].index; ++j) 604 { 605 int prepare_ipp = 0; // Changing the incoming UDP broadcast needs to be done once 606 607 if (iflist[j].index != ifindex_to_exclude) 608 { 609 NVBCR_PRINTF(("Going to sent UDP Broadcast on interface: %s, sock_nr=%d\n", iflistToString(&(iflist[j])), cur_ifsnr[j].sock_nr)); 610 611 memset(&sa, 0, salen); 612 613 sa.sll_family = AF_PACKET; 614 sa.sll_ifindex = iflist[j].index; /* Must be the SIOCGIFINDEX number */ 615 // Set the outgoing hardware address to 1's. True Broadcast 616 sa.sll_addr[0] = sa.sll_addr[1] = sa.sll_addr[2] = sa.sll_addr[3] = 0xff; 617 sa.sll_addr[4] = sa.sll_addr[5] = sa.sll_addr[6] = sa.sll_addr[7] = 0xff; 618 sa.sll_halen = 6; 619 620 /* 621 * htons(ETH_P_IP) is necessary otherwise sendto will 622 * succeed but no packet is actually sent on the wire (this 623 * was the case for PPP interfaces, for ETH interfaces an unknown 624 * LAN frame is sent if htons(ETH_P_IP) is not set as protocol). 625 */ 626 sa.sll_protocol = htons(ETH_P_IP); /* ETH_P_PPP_MP */ 627 628 if (prepare_ipp == 0) { 629 // change TimeToLive to 1, This is to avoid loops, bcrelay will *NOT* relay 630 // anything with TTL==1. 631 ipp_p->ip.ttl = 1; 632 633 // The CRC gets broken here when sending over ipsec tunnels but that 634 // should not matter as we reassemble the packet at the other end. 635 ipp_p->ip.daddr = iflist[j].bcast; 636 637 // check IP srcAddr (on some winXP boxes it is found to be 638 // different from the configured ppp address). 639 // Only do this for PPP interfaces. 640 if ((iflist[i].flags1 & IFLIST_FLAGS1_IF_IS_PPP) && 641 (ntohl(ipp_p->ip.saddr) != iflist[i].ifdstaddr)) 642 { 643 ipp_p->ip.saddr = htonl(iflist[i].ifdstaddr); 644 iflist[i].flags1 |= IFLIST_FLAGS1_CHANGED_INNER_SADDR; 645 } 646 647 // Update IP checkSum (TTL and src/dest IP Address might have changed) 648 ip_update_checksum((unsigned char *)ipp_p); 649 /* Disable upper layer checksum */ 650 udppdu = (unsigned char *)ipp_p + (4 * ipp_p->ip.ihl); 651 *IP_UDPPDU_CHECKSUM_MSB_PTR(udppdu) = (unsigned char)0; 652 *IP_UDPPDU_CHECKSUM_LSB_PTR(udppdu) = (unsigned char)0; 653 654 prepare_ipp = 1; 655 } 656 657 /* 658 * The beauty of sending IP packets on a PACKET socket of type SOCK_DGRAM is that 659 * there is no need to concern about the physical/link layer header because it is 660 * filled in automatically (based on the contents of sa). 661 */ 662 if ((nrsent = sendto(cur_ifsnr[j].sock_nr, ipp_p, rlen, MSG_DONTWAIT|MSG_TRYHARD, (struct sockaddr *)&sa, salen)) < 0) 663 { 664 if (errno == ENETDOWN) { 665 syslog(LOG_NOTICE, "ignored ENETDOWN from sendto(), a network interface was going down?"); 666 } else if (errno == ENXIO) { 667 syslog(LOG_NOTICE, "ignored ENXIO from sendto(), a network interface went down?"); 668 } else if (errno == ENOBUFS) { 669 syslog(LOG_NOTICE, "ignored ENOBUFS from sendto(), temporary shortage of buffer memory"); 670 } else { 671 syslog(LOG_ERR, "mainloop: Error, sendto failed! (rv=%d, errno=%d)", nrsent, errno); 672 exit(1); 673 } 674 } 675 NVBCR_PRINTF(("Successfully relayed %d bytes \n", nrsent)); 676 if (vnologging == 0) { 677 logstr_cntr = sprintf(logstr, "%s ", iflistLogRToString(&(iflist[j]), j, &(cur_ifsnr[j]))); 678 logstr += logstr_cntr; 679 } 680 } 681 } 682 if (vnologging == 0) syslog(LOG_INFO, "%s", log_relayed); 683 } else { 684 NVBCR_PRINTF(("is NOT an UDP BROADCAST (with TTL!=1 and UDP_CHKSUM!=0)\n\n")); 685 } 686 } 687 } 688 /* 689 * Don't forget to discover new interfaces if we keep getting 690 * incoming packets (on an already discovered interface). 691 */ 692 if (no_discifs_cntr == 0) 693 { 694 no_discifs_cntr = MAX_NODISCOVER_IFS; 695 696 /* no_discifs_cntr became 0, rediscover interfaces */ 697 NVBCR_PRINTF(("no_discifs_cntr became 0, rediscover interfaces\n")); 698 copy_ifsnr(cur_ifsnr, old_ifsnr); 699 memset(cur_ifsnr, -1, sizeof(cur_ifsnr)); 700 iflist = discoverActiveInterfaces(); 701 /* 702 * Build new cur_ifsnr list. 703 * Make iflist[i] correspond with cur_ifsnr[i], so iflist[i].index == cur_ifsnr[i].ifindex 704 * The old list (old_ifsnr) is used to compare. 705 */ 706 for (i=0; iflist[i].index; ++i) { 707 /* check to see if it is a NEW interface */ 708 int fsnr = find_sock_nr(old_ifsnr, iflist[i].index); 709 if (fsnr == -1) { 710 /* found new interface, open dedicated socket and bind it to the interface */ 711 if ((cur_ifsnr[i].sock_nr = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { 712 syslog(LOG_ERR, "mainloop: Error, socket error! (rv=%d, errno=%d)", cur_ifsnr[i].sock_nr, errno); 713 exit(1); 714 } 715 bind_to_iface(cur_ifsnr[i].sock_nr, iflist[i].index); 716 ifs_change = 1; 717 } 718 else 719 { 720 /* 721 * not a new interface, socket already openen, interface already 722 * bound. Update cur_ifsnr. 723 */ 724 cur_ifsnr[i].sock_nr = fsnr; 725 } 726 cur_ifsnr[i].ifindex = iflist[i].index; 727 } 728 /* Close disappeared interfaces */ 729 for (i=0; i<MAXIF; ++i) 730 { 731 if ((old_ifsnr[i].sock_nr != -1) && (old_ifsnr[i].ifindex != -1) && 732 (find_sock_nr(cur_ifsnr, old_ifsnr[i].ifindex) == -1)) { 733 NVBCR_PRINTF(("Closing an interface (it disappeared), namely: (s_nr=%d, ifidx=%d)\n", old_ifsnr[i].sock_nr, old_ifsnr[i].ifindex)); 734 close(old_ifsnr[i].sock_nr); 735 old_ifsnr[i].sock_nr = -1; 736 old_ifsnr[i].ifindex = -1; 737 ifs_change = 1; 738 } 739 } 740 if (ifs_change == 1) 741 { 742 NVBCR_PRINTF(("Active interface set changed --> displaying current active interfaces..\n")); 743 if (vnologging == 0) { 744 logstr = log_interfaces; 745 logstr_cntr = sprintf(logstr, "Active interface set changed to: "); 746 logstr += logstr_cntr; 747 } 748 for (i = 0; iflist[i].index; i++) 749 { 750 NVBCR_PRINTF(("\t\tactive interface number: %d, if=(%s), sock_nr=%d\n", i, iflistToString(&(iflist[i])), cur_ifsnr[i].sock_nr)); 751 if (vnologging == 0) { 752 logstr_cntr = sprintf(logstr, "%s ", iflistLogIToString(&(iflist[i]), i, &(cur_ifsnr[i]))); 753 logstr += logstr_cntr; 754 } 755 } 756 if (vnologging == 0) syslog(LOG_INFO, "%s", log_interfaces); 757 ifs_change = 0; 758 } 759 } 760 else 761 { 762 no_discifs_cntr -= MAX_SELECT_WAIT; 763 } 764 } 765 } 766} 767 768// Discover active interfaces 769struct iflist * 770discoverActiveInterfaces(void) { 771 int s; 772 static struct iflist iflist[MAXIF+1]; // Allow for MAXIF interfaces 773 static struct ifconf ifs; 774 int i, j, cntr = 0; 775 regex_t preg; 776 struct ifreq ifrflags, ifr; 777 struct sockaddr_in *sin; 778 779 /* Reset iflist */ 780 memset(iflist, 0, sizeof(iflist)); 781 /* Reset ifs */ 782 memset(&ifs, 0, sizeof(ifs)); 783 784 /* 785 * Open general ethernet socket, only used to discover interfaces. 786 */ 787 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 788 syslog(LOG_INFO,"bcrelay: Error creating socket"); 789 return iflist; 790 } 791 792 //regcomp(&preg, argv[1], REG_ICASE|REG_EXTENDED); 793 regcomp(&preg, interfaces, REG_ICASE|REG_EXTENDED); 794 ifs.ifc_len = MAXIF*sizeof(struct ifreq); 795 ifs.ifc_req = malloc(ifs.ifc_len); 796 ioctl(s, SIOCGIFCONF, &ifs); // Discover active interfaces 797 for (i = 0; i * sizeof(struct ifreq) < ifs.ifc_len && cntr < MAXIF; i++) 798 { 799 if (regexec(&preg, ifs.ifc_req[i].ifr_name, 0, NULL, 0) == 0) { 800 801 /* 802 * Get interface flags and check status and type. 803 * Only if interface is up it will be used. 804 */ 805 memset(&ifrflags, 0, sizeof(ifrflags)); 806 strncpy(ifrflags.ifr_name, ifs.ifc_req[i].ifr_name, strlen(ifs.ifc_req[i].ifr_name)); 807 if (ioctl(s, SIOCGIFFLAGS, &ifrflags) < 0) { 808 syslog(LOG_ERR, "discoverActiveInterfaces: Error, SIOCGIFFLAGS Failed! (errno=%d)", errno); 809 exit(1); 810 } 811 812 if (ifrflags.ifr_flags & IFF_UP) 813 { 814 /* 815 * Get interface index 816 */ 817 ioctl(s, SIOCGIFINDEX, &ifs.ifc_req[i]); 818//Fix 3mar2003 819 //iflist[cntr].index = (char)ifs.ifc_req[i].ifr_ifindex; 820 iflist[cntr].index = ifs.ifc_req[i].ifr_ifindex; 821 822 /* 823 * Get interface name 824 */ 825 for (j=0; (j<sizeof(iflist[cntr].ifname) && j<strlen(ifs.ifc_req[i].ifr_ifrn.ifrn_name)); ++j) 826 iflist[cntr].ifname[j] = ifs.ifc_req[i].ifr_ifrn.ifrn_name[j]; 827 iflist[cntr].ifname[j+1] = '\0'; 828 829 /* 830 * Get local IP address 831 */ 832 memset(&ifr, 0, sizeof(ifr)); 833 ifr.ifr_addr.sa_family = AF_INET; 834 (void)strncpy(ifr.ifr_name, iflist[cntr].ifname, strlen(iflist[cntr].ifname)+1); 835 if (ioctl(s, SIOCGIFADDR, (char *)&ifr) < 0) { 836 syslog(LOG_ERR, "discoverActiveInterfaces: Error, SIOCGIFADDR Failed! (errno=%d)", errno); 837 exit(1); 838 } 839 sin = (struct sockaddr_in *)&ifr.ifr_addr; 840 iflist[cntr].ifaddr = ntohl(sin->sin_addr.s_addr); 841 842 iflist[cntr].flags1 = 0; 843 844 if (ifrflags.ifr_flags & IFF_POINTOPOINT) { 845 /* 846 * Get remote IP address (only for PPP interfaces) 847 */ 848 memset(&ifr, 0, sizeof(ifr)); 849 ifr.ifr_addr.sa_family = AF_INET; 850 (void)strncpy(ifr.ifr_name, iflist[cntr].ifname, strlen(iflist[cntr].ifname)+1); 851 if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifr) < 0) { 852 syslog(LOG_ERR, "discoverActiveInterfaces: Error, SIOCGIFDSTADDR Failed! (errno=%d)", errno); 853 exit(1); 854 } 855 sin = (struct sockaddr_in *)&ifr.ifr_addr; 856 iflist[cntr].ifdstaddr = ntohl(sin->sin_addr.s_addr); 857 858 iflist[cntr].flags1 |= IFLIST_FLAGS1_IF_IS_PPP; 859 iflist[cntr].bcast = INADDR_BROADCAST; 860 } 861 else if (ifrflags.ifr_flags & IFF_BROADCAST) 862 { 863 iflist[cntr].ifdstaddr = 0; 864 iflist[cntr].flags1 |= IFLIST_FLAGS1_IF_IS_ETH; 865 iflist[cntr].bcast = INADDR_BROADCAST; 866 } 867 else 868 { 869 iflist[cntr].ifdstaddr = 0; 870 iflist[cntr].flags1 |= IFLIST_FLAGS1_IF_IS_UNKNOWN; 871 iflist[cntr].bcast = INADDR_BROADCAST; 872 } 873 874 cntr++; 875 } 876 // IPSEC tunnels are a fun one. We must change the destination address 877 // so that it will be routed to the correct tunnel end point. 878 // We can define several tunnel end points for the same ipsec interface. 879 } else if (ipsec && *ipsec && strncmp(ifs.ifc_req[i].ifr_name, "ipsec", 5) == 0) { 880 if (strncmp(ifs.ifc_req[i].ifr_name, ipsec, 6) == 0) { 881 struct hostent *hp = gethostbyname(ipsec+7); 882 ioctl(s, SIOCGIFINDEX, &ifs.ifc_req[i]); 883 iflist[cntr].index = ifs.ifc_req[i].ifr_ifindex; /* Store the SIOCGIFINDEX number */ 884 memcpy(&(iflist[cntr++].bcast), hp->h_addr, sizeof(u_int32_t)); 885 } 886 } 887 } 888 889 iflist[cntr].index = 0; // Terminate list 890 free(ifs.ifc_req); // Stop that leak. 891 regfree(&preg); 892 if (s >= 0) 893 close(s); 894 895 return iflist; 896} 897 898 899 900unsigned int ip_compute_checksum(unsigned char *ippdu, int hlen) 901{ 902 unsigned int sum = 0, temp; 903 unsigned char *p; 904 unsigned char cs_msb; 905 unsigned char cs_lsb; 906 907 /* Save original checksum */ 908 cs_msb = *IP_IPPDU_CHECKSUM_MSB_PTR(ippdu); 909 cs_lsb = *IP_IPPDU_CHECKSUM_LSB_PTR(ippdu); 910 911 *IP_IPPDU_CHECKSUM_MSB_PTR(ippdu) = 0; 912 *IP_IPPDU_CHECKSUM_LSB_PTR(ippdu) = 0; 913 914 p = ippdu; 915 hlen /= 2; /* We'll compute taking two bytes a a time */ 916 while(hlen--) { sum += ((*p * 256) + *(p + 1)); p += 2; } 917 while ((temp = (sum >> 16))) { sum = (temp + (sum & 0xFFFF)); } 918 919 /* Restore original checksum */ 920 *IP_IPPDU_CHECKSUM_MSB_PTR(ippdu) = cs_msb; 921 *IP_IPPDU_CHECKSUM_LSB_PTR(ippdu) = cs_lsb; 922 923 return(~sum & 0xFFFF); 924} 925 926void ip_update_checksum(unsigned char *ippdu) 927{ 928 unsigned int cs; 929 930 cs = ip_compute_checksum(ippdu, 4 * IP_IPPDU_IHL(ippdu)); 931 932 *IP_IPPDU_CHECKSUM_MSB_PTR(ippdu) = (unsigned char)((cs >> 8) & 0xFF); 933 *IP_IPPDU_CHECKSUM_LSB_PTR(ippdu) = (unsigned char)(cs & 0xFF); 934} 935 936 937static char *IpProtToString( unsigned char prot ) 938{ 939 switch( prot ) 940 { 941 case 0x11: 942 return "UDP"; 943 case 0x6: 944 return "TCP"; 945 case 0x2f: 946 return "GRE"; 947 case 0x1: 948 return "ICMP"; 949 default: 950 return "???"; 951 } 952} 953 954static char *iflistToString( struct iflist *ifp ) 955{ 956 static char str_tr[80+1]; 957 958 sprintf(str_tr, "index=%d, ifname=%s, ifaddr=%ld.%ld.%ld.%ld, ifdstaddr=%ld.%ld.%ld.%ld, flags1=0x%04lx", 959 ifp->index, ifp->ifname, 960 (ifp->ifaddr)>>24, ((ifp->ifaddr)&0x00ff0000)>>16, ((ifp->ifaddr)&0x0000ff00)>>8, (ifp->ifaddr)&0x000000ff, 961 (ifp->ifdstaddr)>>24, ((ifp->ifdstaddr)&0x00ff0000)>>16, ((ifp->ifdstaddr)&0x0000ff00)>>8, 962 (ifp->ifdstaddr)&0x000000ff, ifp->flags1); 963 964 return str_tr; 965} 966 967static char *iflistLogRToString( struct iflist *ifp, int idx, struct ifsnr *ifnr ) 968{ 969 static char str_tr[MAX_IFLOGTOSTR]; /* 970 * This makes function: 1) non-reentrant (doesn't matter). 971 * 2) not useable multiple times by (s)printf. 972 */ 973 sprintf(str_tr, "%s", ifp->ifname); 974 return str_tr; 975} 976 977static char *iflistLogIToString( struct iflist *ifp, int idx, struct ifsnr *ifnr ) 978{ 979 static char str_tr[MAX_IFLOGTOSTR]; /* 980 * This makes function: 1) non-reentrant (doesn't matter). 981 * 2) not useable multiple times by (s)printf. 982 */ 983 sprintf(str_tr, "%s(%d/%d/%d)", ifp->ifname, idx, ifp->index, ifnr->sock_nr); 984 return str_tr; 985} 986 987static void bind_to_iface(int fd, int ifindex) 988{ 989#ifdef __linux__ 990 static const struct sock_filter filter_instr[] = { 991 /* ip.protocol == IPPROTO_UDP */ 992 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9), 993 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 9), 994 /* ip.daddr & 0x000000ff == 0x000000ff */ 995 BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 16), 996 BPF_STMT(BPF_ALU|BPF_AND|BPF_K, 0x000000ff), 997 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x000000ff, 0, 6), 998 /* ip.ttl != 1 */ 999 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 8), 1000 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 1, 4, 0), 1001 /* udp.checksum != 0 */ 1002 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), 1003 BPF_STMT(BPF_LD|BPF_H|BPF_IND, 6), 1004 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0, 1, 0), 1005 /* accept packet */ 1006 BPF_STMT(BPF_RET|BPF_K, 0xffffffff), 1007 /* discard packet */ 1008 BPF_STMT(BPF_RET|BPF_K, 0), 1009 }; 1010 static const struct sock_fprog filter = { 1011 .len = sizeof(filter_instr) / sizeof(filter_instr[0]), 1012 .filter = (struct sock_filter *) filter_instr, 1013 }; 1014#endif 1015 struct sockaddr_ll sll; 1016 1017 memset(&sll, 0, sizeof(sll)); 1018 sll.sll_family = AF_PACKET; 1019 sll.sll_ifindex = ifindex; 1020 sll.sll_protocol = htons(ETH_P_IP); 1021 1022 if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1) { 1023 syslog(LOG_ERR, "bind_to_iface: Error, bind failed! (rv=-1, errno=%d)", errno); 1024 exit(1); 1025 } 1026 1027#ifdef __linux__ 1028 /* Ignoring error (kernel may lack support for this) */ 1029 setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)); 1030#endif 1031} 1032 1033static void copy_ifsnr(struct ifsnr *from, struct ifsnr *to) 1034{ 1035 int i; 1036 1037 for (i=0; i<MAXIF; ++i) 1038 { 1039 to[i].sock_nr = from[i].sock_nr; 1040 to[i].ifindex = from[i].ifindex; 1041 } 1042} 1043 1044static int find_sock_nr(struct ifsnr *l, int ifidx) 1045{ 1046 int i; 1047 1048 for (i=0; i<MAXIF; ++i) 1049 if (l[i].ifindex == ifidx) return l[i].sock_nr; 1050 /* not found */ 1051 return -1; 1052} 1053 1054