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