1
0

bcrelay.c 38 KB

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