• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/accel-pptpd/pptpd-1.3.3/
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