1 /*
2  * $Id: getoutaddr.c,v 1.140.4.3.2.3 2017/01/31 08:17:38 karls Exp $
3  *
4  * Copyright (c) 2001, 2002, 2006, 2008, 2009, 2010, 2011, 2012, 2013, 2014,
5  *               2016, 2017
6  *      Inferno Nettverk A/S, Norway.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. The above copyright notice, this list of conditions and the following
12  *    disclaimer must appear in all copies of the software, derivative works
13  *    or modified versions, and any portions thereof, aswell as in all
14  *    supporting documentation.
15  * 2. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by
18  *      Inferno Nettverk A/S, Norway.
19  * 3. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Inferno Nettverk A/S requests users of this software to return to
34  *
35  *  Software Distribution Coordinator  or  sdc@inet.no
36  *  Inferno Nettverk A/S
37  *  Oslo Research Park
38  *  Gaustadall�en 21
39  *  NO-0349 Oslo
40  *  Norway
41  *
42  * any improvements or extensions that they make and grant Inferno Nettverk A/S
43  * the rights to redistribute these changes.
44  *
45  */
46 
47 #include "common.h"
48 
49 static const char rcsid[] =
50 "$Id: getoutaddr.c,v 1.140.4.3.2.3 2017/01/31 08:17:38 karls Exp $";
51 
52 static int
53 addrscope_matches(const struct sockaddr_in6 *addr,
54                   const ipv6_addrscope_t addrscope);
55 /*
56  * Returns true if address-scope "addrscope" matches the address scope
57  * of address "addr".
58  */
59 
60 static int
61 ifname_matches(const char *ifname, const uint32_t ifindex);
62 /*
63  * Returns true if there is an interface with the name "ifname", and
64  * the index of this interface is "ifinxex".
65  *
66  * Returns false otherwise.
67  */
68 
69 static sa_family_t
70 get_external_safamily(const struct sockaddr_storage *client,
71                       const int command, const sockshost_t *reqhost);
72 /*
73  * Returns the sa_family_t that should be used for a client with address
74  * "client", requesting the SOCKS command "command" with the request host
75  * "reqhost".
76  *
77  * On success the sa_family_t that should be used.
78  * On failure returns AF_UNSPEC.
79  */
80 
81 
82 static struct sockaddr_storage *
83 getdefaultexternal(const sa_family_t safamily, ipv6_addrscope_t addrscope,
84                    const uint32_t ifindex, struct sockaddr_storage *addr);
85 /*
86  * Returns the default IP address of sa_family_t "safamily" to use for
87  * external connections.  The portnumber in the address returned should
88  * be ignored.
89  *
90  * "safamily" can be set to AF_UNSPEC if the function can return an
91  * address of any sa_family_t.  If there is no address of type safamily
92  * available, the semantics are the same as if safamily was set to AF_UNSPEC.
93  *
94  * "addrscope" indicates the scopeid of the external addresses we want
95  * returned.  "addrscope" only applies if "safamily" is AF_INET6.
96  * If "addrscope" is addrscope_linklocal, "ifindex" indicates the interface
97  * the returned address should be configured on.  Otherwise, "ifindex" is
98  * ignored.
99  *
100  * The ipaddress to use is stored in "addr", and a pointer to it is returned.
101  */
102 
103 struct sockaddr_storage *
getoutaddr(laddr,client_l,client_r,cmd,reqhost,emsg,emsglen)104 getoutaddr(laddr, client_l, client_r, cmd, reqhost, emsg, emsglen)
105    struct sockaddr_storage *laddr;
106    const struct sockaddr_storage *client_l;
107    const struct sockaddr_storage *client_r;
108    const int cmd;
109    const sockshost_t *reqhost;
110    char *emsg;
111    const size_t emsglen;
112 {
113    const char *function = "getoutaddr()";
114    struct sockaddr_storage raddr;
115    char addrstr[MAXSOCKADDRSTRING], raddrstr[MAXSOCKSHOSTSTRING];
116 
117    slog(LOG_DEBUG,
118         "%s: client %s, cmd %s, reqhost %s, external.rotation = %s",
119         function,
120         sockaddr2string(client_r, addrstr, sizeof(addrstr)),
121         command2string(cmd),
122         sockshost2string(reqhost, raddrstr, sizeof(raddrstr)),
123         rotation2string(sockscf.external.rotation));
124 
125    bzero(&raddr, sizeof(raddr));
126 
127    /*
128     * First figure out what /type/ of address (ipv4 or ipv6) we need to
129     * bind on the external side.
130     */
131    switch (cmd) {
132       case SOCKS_BIND:
133          if (reqhost->atype            == SOCKS_ADDR_IPV4
134          &&  reqhost->addr.ipv4.s_addr == htonl(BINDEXTENSION_IPADDR))
135             SET_SOCKADDR(&raddr, external_has_global_safamily(AF_INET) ?
136                                  AF_INET : AF_INET6);
137          else if (reqhost->atype == SOCKS_ADDR_IPV4
138          ||       reqhost->atype == SOCKS_ADDR_IPV6)
139             sockshost2sockaddr(reqhost, &raddr);
140          else {
141             /*
142              * Have to expect the bindreply from an address given as a
143              * hostname by the client.  Since we may have multiple address
144              * families configured on the external interface on which we
145              * can accept the bindreply on, we need to bind an address of
146              * the correct type.
147              *
148              * For now we assume that the type of address returned first
149              * is the type of address we should bind.
150              */
151             int gaierr;
152 
153             SASSERTX(reqhost->atype == SOCKS_ADDR_DOMAIN);
154 
155             sockshost2sockaddr2(reqhost, &raddr, &gaierr, emsg, emsglen);
156             if (gaierr != 0) {
157                log_resolvefailed(reqhost->addr.domain, EXTERNALIF, gaierr);
158                return NULL;
159             }
160          }
161 
162          break;
163 
164       case SOCKS_CONNECT:
165       case SOCKS_UDPASSOCIATE: {
166          int gaierr;
167 
168          sockshost2sockaddr2(reqhost, &raddr, &gaierr, emsg, emsglen);
169          if (gaierr != 0) {
170             SASSERTX(reqhost->atype == SOCKS_ADDR_DOMAIN);
171 
172             log_resolvefailed(reqhost->addr.domain, EXTERNALIF, gaierr);
173             return NULL;
174          }
175 
176          break;
177       }
178 
179       default:
180          SERRX(cmd);
181    }
182 
183    switch (sockscf.external.rotation) {
184       case ROTATION_NONE:
185          /*
186           * We have a complicating factor here regarding IPv6 scopeids.
187           * If the target destination is specified with a non-global
188           * scopeid (e.g. a link-local address), we need to bind an address
189           * not only of the same type, but on the *same link/interface* too.
190           */
191 
192          getdefaultexternal(raddr.ss_family,
193                             raddr.ss_family == AF_INET6 ?
194                                 ipv6_addrscope(&TOIN6(&raddr)->sin6_addr)
195                               : addrscope_global,
196                             TOIN6(&raddr)->sin6_scope_id,
197                             laddr);
198          break;
199 
200       case ROTATION_SAMESAME:
201          if (client_l->ss_family == raddr.ss_family)
202             *laddr = *client_l;
203          else {
204             snprintf(emsg, emsglen,
205                      "rotation for external addresses is set to %s, but "
206                      "that can not work for this %s request.  "
207                      "The internal address we accepted the client on is "
208                      "a %s (%s), but the target address is a %s (%s)",
209                      rotation2string(sockscf.external.rotation),
210                      command2string(cmd),
211                      safamily2string(client_l->ss_family),
212                      sockaddr2string(client_l, NULL, 0),
213                      safamily2string(raddr.ss_family),
214                      sockaddr2string(&raddr, raddrstr, sizeof(raddrstr)));
215 
216             swarnx("%s: %s", function, emsg);
217             return NULL;
218          }
219 
220          break;
221 
222       case ROTATION_ROUTE: {
223          if (IPADDRISBOUND(&raddr)) {
224             /*
225              * Connect a udp socket and check what local address was chosen
226              * by the kernel for connecting to dst.  Idea from Quagga source.
227              */
228             sockshost_t host;
229             int s;
230 
231             if ((s = socket(raddr.ss_family, SOCK_DGRAM, 0)) == -1) {
232                snprintf(emsg, emsglen,
233                         "could not create new %s UDP socket with socket(2): %s",
234                         safamily2string(raddr.ss_family), strerror(errno));
235 
236                swarn("%s: %s", function, emsg);
237                return NULL;
238             }
239 
240             if (!PORTISBOUND(&raddr))
241                /* use any valid portnumber. This is just a dry-run */
242                SET_SOCKADDRPORT(&raddr, 1);
243 
244             sockaddr2sockshost(&raddr, &host);
245             if (socks_connecthost(s,
246                                   EXTERNALIF,
247                                   &host,
248                                   laddr,
249                                   NULL,
250                                   -1,
251                                   emsg,
252                                   emsglen) == -1) {
253                slog(LOG_DEBUG, "%s: %s", function, emsg);
254                close(s);
255 
256                if (cmd == SOCKS_UDPASSOCIATE)
257                   return NULL;
258 
259                /*
260                 * Else: continue.
261                 * While highly unlikely it will work later, when we actually
262                 * do try to connect/send data, it could be the local (but
263                 * external to Dante) configuration is to block udp packets to
264                 * this destination, but allow tcp.
265                 */
266                getdefaultexternal(raddr.ss_family,
267                                   raddr.ss_family == AF_INET6 ?
268                                        ipv6_addrscope(&TOIN6(&raddr)->sin6_addr)
269                                     :  addrscope_global,
270                                   TOIN6(&raddr)->sin6_scope_id,
271                                   laddr);
272                break;
273             }
274 
275             close(s);
276          }
277          else
278             getdefaultexternal(get_external_safamily(client_r, cmd, reqhost),
279                                addrscope_global,
280                                0,
281                                laddr);
282 
283          break;
284       }
285 
286       default:
287          SERRX(sockscf.external.rotation);
288    }
289 
290    if (addrindex_on_externallist(&sockscf.external, laddr) != -1)
291       slog(LOG_DEBUG,
292            "%s: local address %s selected for forwarding from client %s to %s",
293            function,
294            sockaddr2string2(laddr,  0, addrstr,  sizeof(addrstr)),
295            sockaddr2string(client_r, NULL, 0),
296            sockaddr2string(&raddr, raddrstr, sizeof(raddrstr)));
297    else {
298       char rotation[256];
299 
300       if (sockscf.external.rotation == ROTATION_NONE)
301          *rotation = NUL; /* default.  Don't print anything confusing. */
302       else
303          snprintf(rotation, sizeof(rotation),
304                   "using external.rotation = %s, ",
305                   rotation2string(sockscf.external.rotation));
306 
307       if (IPADDRISBOUND(laddr))
308          snprintf(emsg, emsglen,
309                   "%slocal address %s was selected for forwarding from our "
310                   "local client %s to target %s, but that local address is "
311                   "not set on our external interface(s).  Configuration "
312                   "error in %s?",
313                   rotation,
314                   sockaddr2string2(laddr,  0, addrstr,  sizeof(addrstr)),
315                   sockaddr2string(client_r, NULL,     0),
316                   sockaddr2string(&raddr, raddrstr, sizeof(raddrstr)),
317                   sockscf.option.configfile);
318       else
319          snprintf(emsg, emsglen,
320                   "%snone of the addresses configured on our external "
321                   "interface(s) can be used for forwarding from our local "
322                   "client %s to target %s.  Configuration error in %s?",
323                   rotation,
324                   sockaddr2string(client_r, NULL, 0),
325                   sockaddr2string(&raddr, raddrstr, sizeof(raddrstr)),
326                   sockscf.option.configfile);
327 
328       /*
329        * Assume that if the user has not configured any such address,
330        * his intention is to not support that af (e.g., support only
331        * ipv4).  If he has configured such an address, but we could for
332        * some reason not use it, it's more likely to be a configuration
333        * error though, so warn.
334        */
335       slog(external_has_safamily(laddr->ss_family) ? LOG_WARNING : LOG_DEBUG,
336            "%s: %s", function, emsg);
337 
338       return NULL;
339    }
340 
341    /*
342     * Try to set the local port to the best value also, though this is mostly
343     * just guessing for all but the bind-case.
344     */
345    switch (cmd) {
346 #if SOCKS_SERVER
347       case SOCKS_BIND:
348          if (reqhost->atype            == SOCKS_ADDR_IPV4
349          &&  reqhost->addr.ipv4.s_addr == htonl(BINDEXTENSION_IPADDR))
350             SET_SOCKADDRPORT(laddr, GET_SOCKADDRPORT(client_r));
351          else if (  (raddr.ss_family == AF_INET
352                   && TOIN(&raddr)->sin_addr.s_addr == htonl(INADDR_ANY))
353                ||    (raddr.ss_family == AF_INET6
354                   && memcmp(&TOIN6(&raddr)->sin6_addr,
355                             &in6addr_any,
356                             sizeof(in6addr_any)) == 0))
357             SET_SOCKADDRPORT(laddr, reqhost->port);
358          else
359             SET_SOCKADDRPORT(laddr, htons(0));
360 
361          break;
362 #endif /* SOCKS_SERVER */
363 
364       case SOCKS_CONNECT:
365       case SOCKS_UDPASSOCIATE: /* reqhost is the target of the first packet. */
366          SET_SOCKADDRPORT(laddr, GET_SOCKADDRPORT(client_r));
367          break;
368 
369       default:
370          SERRX(cmd);
371    }
372 
373    SASSERTX(IPADDRISBOUND(laddr));
374 
375    return laddr;
376 }
377 
378 struct sockaddr_storage *
getinaddr(laddr,_client,emsg,emsglen)379 getinaddr(laddr, _client, emsg, emsglen)
380    struct sockaddr_storage *laddr;
381    const struct sockaddr_storage *_client;
382    char *emsg;
383    const size_t emsglen;
384 {
385    const char *function = "getinaddr()";
386    struct sockaddr_storage client;
387    size_t i;
388    int wildcard_address_found = 0;
389 
390    slog(LOG_DEBUG, "%s: client %s",
391         function, sockaddr2string(_client, NULL, 0));
392 
393    SASSERTX(_client->ss_family == AF_INET || _client->ss_family == AF_INET6);
394 
395    sockaddrcpy(&client, _client, sizeof(client));
396 
397    /*
398     * Just return the first address of the appropriate type from our
399     * internal list and hope the best.
400     */
401    for (i = 0; i < sockscf.internal.addrc; ++i) {
402       if (sockscf.internal.addrv[i].addr.ss_family == client.ss_family) {
403          if (IPADDRISBOUND(&sockscf.internal.addrv[i].addr)) {
404             sockaddrcpy(laddr, &sockscf.internal.addrv[i].addr, sizeof(*laddr));
405 
406             slog(LOG_DEBUG, "%s: address %s selected",
407                  function, sockaddr2string(laddr, NULL, 0));
408 
409             return laddr;
410          }
411          else
412             wildcard_address_found = 1;
413       }
414    }
415 
416    if (wildcard_address_found)
417       snprintf(emsg, emsglen,
418                "no specific %s found amongst the internal addresses, only "
419                "an unbound wildcard address found.  This client requires "
420                "an internal IP-address to be specified in %s however",
421                safamily2string(client.ss_family), SOCKD_CONFIGFILE);
422    else
423       snprintf(emsg, emsglen, "no %s found amongst the internal addresses",
424                safamily2string(client.ss_family));
425 
426    slog(wildcard_address_found ? LOG_NOTICE : LOG_DEBUG,
427         "%s: %s", function, emsg);
428 
429    return NULL;
430 }
431 
432 static struct sockaddr_storage *
getdefaultexternal(safamily,addrscope,ifindex,addr)433 getdefaultexternal(safamily, addrscope, ifindex, addr)
434    const sa_family_t safamily;
435    const ipv6_addrscope_t addrscope;
436    const uint32_t ifindex;
437    struct sockaddr_storage *addr;
438 {
439    const char *function = "getdefaultexternal()";
440    const char *safamilystring  = (safamily == AF_UNSPEC ?
441                                    "<any address>" : safamily2string(safamily));
442    const char *addrscopestring = addrscope2string(addrscope);
443    size_t i, addrfound;
444 
445    slog(LOG_DEBUG, "%s: looking for an %s with scopeid %d/%s, ifindex %d",
446         function, safamilystring, addrscope, addrscopestring, ifindex);
447 
448    for (i = 0, addrfound = 0; i < sockscf.external.addrc && !addrfound; ++i) {
449       switch (sockscf.external.addrv[i].atype) {
450          case SOCKS_ADDR_IFNAME: {
451             struct sockaddr_storage mask;
452 
453             size_t ii = 0;
454             while (ifname2sockaddr(sockscf.external.addrv[i].addr.ifname,
455                                    ii++,
456                                    addr,
457                                    &mask) != NULL) {
458                if (safamily == AF_UNSPEC || addr->ss_family == safamily) {
459                   if (safamily == AF_INET6) {
460                      if (!addrscope_matches(TOIN6(addr), addrscope))
461                         continue;
462 
463                      if (addrscope == addrscope_linklocal
464                      && !ifname_matches(sockscf.external.addrv[i].addr.ifname,
465                                         ifindex))
466                         continue;
467                   }
468 
469                   addrfound = 1;
470                   break;
471                }
472             }
473 
474             break;
475          }
476 
477          case SOCKS_ADDR_IPV4:
478          case SOCKS_ADDR_IPV6:
479             if (safamily != AF_UNSPEC
480             &&  safamily != atype2safamily(sockscf.external.addrv[i].atype)) {
481                slog(LOG_DEBUG,
482                     "%s: atype of address %s does not match atype %s",
483                     function,
484                     ruleaddr2string(&sockscf.external.addrv[i],
485                                     ADDRINFO_ATYPE,
486                                     NULL,
487                                     0),
488                     safamily2string(safamily));
489                continue;
490             }
491 
492             sockshost2sockaddr(ruleaddr2sockshost(&sockscf.external.addrv[i],
493                                                   NULL,
494                                                   SOCKS_TCP),
495                                addr);
496 
497             if (addr->ss_family == AF_INET6) {
498                const char *ifname;
499 
500                if (addrscope == addrscope_nodelocal)
501                   /*
502                    * a nodelocal address should be able to reach any
503                    * other nodelocal address.
504                    */
505                   ;
506                else if (!addrscope_matches(TOIN6(addr), addrscope))
507                   continue;
508 
509                 if ((ifname = sockaddr2ifname(addr, NULL, 0)) == NULL) {
510                   swarnx("%s: could not find any interface with address %s",
511                          function, sockaddr2string(addr, NULL, 0));
512 
513                   continue;
514                }
515 
516                if (addrscope == addrscope_linklocal
517                && !ifname_matches(ifname, ifindex))
518                   continue;
519             }
520 
521             addrfound = 1;
522             break;
523 
524          default:
525             SERRX((*sockscf.external.addrv).atype);
526       }
527    }
528 
529    if (addrfound)
530       slog(LOG_DEBUG, "%s: matched %s %s",
531            function,
532            safamilystring,
533            sockaddr2string2(addr, ADDRINFO_SCOPEID | ADDRINFO_PORT, NULL, 0));
534    else {
535       slog(LOG_DEBUG,
536            "%s: no matching %s found on external list, using INADDR_ANY",
537            function, safamilystring);
538 
539       bzero(addr, sizeof(*addr));
540       SET_SOCKADDR(addr, safamily == AF_UNSPEC ? AF_INET : safamily);
541    }
542 
543    return addr;
544 }
545 
546 sa_family_t
get_external_safamily(client,command,reqhost)547 get_external_safamily(client, command, reqhost)
548    const struct sockaddr_storage *client;
549    const int command;
550    const sockshost_t *reqhost;
551 {
552    const char *function = "get_external_safamily()";
553    sa_family_t safamily;
554 
555    switch (command) {
556       case SOCKS_BIND:
557       case SOCKS_UDPASSOCIATE:
558          switch (reqhost->atype) {
559             case SOCKS_ADDR_IPV4:
560             case SOCKS_ADDR_IPV6:
561                safamily = atype2safamily(reqhost->atype);
562                break;
563 
564             case SOCKS_ADDR_DOMAIN: {
565                struct sockaddr_storage p;
566 
567                sockshost2sockaddr(reqhost, &p);
568                if (IPADDRISBOUND(&p))
569                   safamily = p.ss_family;
570                else
571                   safamily = client->ss_family;
572 
573                break;
574             }
575 
576             default:
577                SERRX(reqhost->atype);
578          }
579          break;
580 
581       case SOCKS_CONNECT: {
582          struct sockaddr_storage p;
583 
584          sockshost2sockaddr(reqhost, &p);
585          if (IPADDRISBOUND(&p))
586             safamily = p.ss_family;
587          else
588             safamily = client->ss_family;
589 
590          break;
591       }
592 
593       default:
594          SERRX(command);
595    }
596 
597    if (external_has_safamily(safamily))
598       return safamily;
599 
600    /*
601     * Do not have the optimal safamily.  Anything else we can try?
602     */
603    switch (safamily) {
604       case AF_INET:
605          if (external_has_safamily(AF_INET6))
606             return AF_INET6;
607 
608          break;
609 
610       case AF_INET6:
611          if (external_has_safamily(AF_INET))
612             return AF_INET;
613 
614          break;
615 
616       default:
617          SERRX(safamily);
618    }
619 
620    swarnx("%s: strange ... could not find any address to bind on external side "
621           "for command %s from client %s.  Reqhost is %s.  "
622           "Have IPv4? %s.  IPv6? %s",
623           function,
624           command2string(command),
625           sockaddr2string(client, NULL, 0),
626           sockshost2string(reqhost, NULL, 0),
627           external_has_safamily(AF_INET)  ? "Yes" : "No",
628           external_has_safamily(AF_INET6) ?
629                  external_has_global_safamily(AF_INET6) ?
630                     "Yes (global)" : "Yes (local only)"
631               :  "No");
632 
633    return AF_UNSPEC;
634 }
635 
636 static int
addrscope_matches(addr,scope)637 addrscope_matches(addr, scope)
638    const struct sockaddr_in6 *addr;
639    const ipv6_addrscope_t scope;
640 {
641    const char *function = "addrscope_matches()";
642    const ipv6_addrscope_t addrscope = ipv6_addrscope(&addr->sin6_addr);
643 
644    if (addrscope == scope)
645       return 1;
646 
647    if (scope      == addrscope_nodelocal
648    &&  addrscope  == addrscope_global)
649       /*
650        * a locally configured global address should be able to connect
651        * to any nodelocal address, but a linklocal address will not
652        * necessarily be able to connect to a nodelocal one, for some
653        * reason.  That at least appears to be the case on FreeBSD 9.1.
654        */
655       return 1;
656 
657    if (sockscf.option.debug)
658       slog(LOG_DEBUG,
659            "%s: skipping address %s with system scopeid "
660            "0x%x (internal: %d/%s) while searching for "
661            "address with internal scopeid %d/%s",
662            function,
663            sockaddr2string(TOCSS(addr), NULL, 0),
664            addr->sin6_scope_id,
665            ipv6_addrscope(&addr->sin6_addr),
666            addrscope2string(ipv6_addrscope(&addr->sin6_addr)),
667            (int)scope,
668            addrscope2string(scope));
669 
670    return 0;
671 }
672 
673 static int
ifname_matches(ifname,ifindex)674 ifname_matches(ifname, ifindex)
675    const char *ifname;
676    const uint32_t ifindex;
677 {
678    const char *function = "ifname_matches()";
679    uint32_t ifnameindex;
680    int matches;
681 
682    if ((ifnameindex = if_nametoindex(ifname)) == 0) {
683       swarn("%s: if_nametoindex(%s) failed", function, ifname);
684       return 0;
685    }
686 
687    matches = (ifnameindex == ifindex);
688 
689    slog(LOG_DEBUG, "%s: ifname %s/ifindex %u %s ifindex %u",
690         function,
691         ifname,
692         ifnameindex,
693         matches ? "matches" : "does not match",
694         ifindex);
695 
696    return matches;
697 }
698