Annotation of embedaddon/miniupnpd/minissdpd/getroute.c, revision 1.1.1.1

1.1       misho       1: /* $Id: getroute.c,v 1.4 2014/12/01 09:07:17 nanard Exp $ */
                      2: /* MiniUPnP project
                      3:  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
                      4:  * (c) 2006-2014 Thomas Bernard
                      5:  * This software is subject to the conditions detailed
                      6:  * in the LICENCE file provided within the distribution */
                      7: 
                      8: #include <stdio.h>
                      9: #include <string.h>
                     10: #include <unistd.h>
                     11: #include <errno.h>
                     12: #include <syslog.h>
                     13: #include <sys/types.h>
                     14: #include <sys/socket.h>
                     15: #include <netinet/in.h>
                     16: #ifdef __linux__
                     17: /*#include <linux/in_route.h>*/
                     18: #include <linux/netlink.h>
                     19: #include <linux/rtnetlink.h>
                     20: #include <libnfnetlink/libnfnetlink.h>
                     21: #else /* __linux__ */
                     22: #include <net/if.h>
                     23: #include <net/route.h>
                     24: #include <netinet/in.h>
                     25: #ifdef AF_LINK
                     26: #include <net/if_dl.h>
                     27: #endif /* AF_LINK */
                     28: #endif /* __linux__ */
                     29: 
                     30: #include "getroute.h"
                     31: #include "upnputils.h"
                     32: #include "config.h"
                     33: 
                     34: /* get_src_for_route_to() function is only called in code
                     35:  * enabled with ENABLE_IPV6 */
                     36: #ifdef ENABLE_IPV6
                     37: 
                     38: int
                     39: get_src_for_route_to(const struct sockaddr * dst,
                     40:                      void * src, size_t * src_len,
                     41:                      int * index)
                     42: {
                     43: #if __linux__
                     44:        int fd = -1;
                     45:        struct nlmsghdr *h;
                     46:        int status;
                     47:        struct {
                     48:                struct nlmsghdr n;
                     49:                struct rtmsg r;
                     50:                char buf[1024];
                     51:        } req;
                     52:        struct sockaddr_nl nladdr;
                     53:        struct iovec iov = {
                     54:                .iov_base = (void*) &req.n,
                     55:        };
                     56:        struct msghdr msg = {
                     57:                .msg_name = &nladdr,
                     58:                .msg_namelen = sizeof(nladdr),
                     59:                .msg_iov = &iov,
                     60:                .msg_iovlen = 1,
                     61:        };
                     62:        const struct sockaddr_in * dst4;
                     63:        const struct sockaddr_in6 * dst6;
                     64: 
                     65:        memset(&req, 0, sizeof(req));
                     66:        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
                     67:        req.n.nlmsg_flags = NLM_F_REQUEST;
                     68:        req.n.nlmsg_type = RTM_GETROUTE;
                     69:        req.r.rtm_family = dst->sa_family;
                     70:        req.r.rtm_table = 0;
                     71:        req.r.rtm_protocol = 0;
                     72:        req.r.rtm_scope = 0;
                     73:        req.r.rtm_type = 0;
                     74:        req.r.rtm_src_len = 0;
                     75:        req.r.rtm_dst_len = 0;
                     76:        req.r.rtm_tos = 0;
                     77: 
                     78:        {
                     79:                char dst_str[128];
                     80:                sockaddr_to_string(dst, dst_str, sizeof(dst_str));
                     81:                syslog(LOG_DEBUG, "get_src_for_route_to (%s)", dst_str);
                     82:        }
                     83:        /* add address */
                     84:        if(dst->sa_family == AF_INET) {
                     85:                dst4 = (const struct sockaddr_in *)dst;
                     86:                nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst4->sin_addr, 4);
                     87:                req.r.rtm_dst_len = 32;
                     88:        } else {
                     89:                dst6 = (const struct sockaddr_in6 *)dst;
                     90:                nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst6->sin6_addr, 16);
                     91:                req.r.rtm_dst_len = 128;
                     92:        }
                     93: 
                     94:        fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
                     95:        if (fd < 0) {
                     96:                syslog(LOG_ERR, "socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) : %m");
                     97:                return -1;
                     98:        }
                     99: 
                    100:        memset(&nladdr, 0, sizeof(nladdr));
                    101:        nladdr.nl_family = AF_NETLINK;
                    102: 
                    103:        req.n.nlmsg_seq = 1;
                    104:        iov.iov_len = req.n.nlmsg_len;
                    105: 
                    106:        status = sendmsg(fd, &msg, 0);
                    107: 
                    108:        if (status < 0) {
                    109:                syslog(LOG_ERR, "sendmsg(rtnetlink) : %m");
                    110:                goto error;
                    111:        }
                    112: 
                    113:        memset(&req, 0, sizeof(req));
                    114: 
                    115:        for(;;) {
                    116:                iov.iov_len = sizeof(req);
                    117:                status = recvmsg(fd, &msg, 0);
                    118:                if(status < 0) {
                    119:                        if (errno == EINTR || errno == EAGAIN)
                    120:                                continue;
                    121:                        syslog(LOG_ERR, "recvmsg(rtnetlink) %m");
                    122:                        goto error;
                    123:                }
                    124:                if(status == 0) {
                    125:                        syslog(LOG_ERR, "recvmsg(rtnetlink) EOF");
                    126:                        goto error;
                    127:                }
                    128:                for (h = (struct nlmsghdr*)&req.n; status >= (int)sizeof(*h); ) {
                    129:                        int len = h->nlmsg_len;
                    130:                        int l = len - sizeof(*h);
                    131: 
                    132:                        if (l<0 || len>status) {
                    133:                                if (msg.msg_flags & MSG_TRUNC) {
                    134:                                        syslog(LOG_ERR, "Truncated message");
                    135:                                }
                    136:                                syslog(LOG_ERR, "malformed message: len=%d", len);
                    137:                                goto error;
                    138:                        }
                    139: 
                    140:                        if(nladdr.nl_pid != 0 || h->nlmsg_seq != 1/*seq*/) {
                    141:                                syslog(LOG_ERR, "wrong seq = %d\n", h->nlmsg_seq);
                    142:                                /* Don't forget to skip that message. */
                    143:                                status -= NLMSG_ALIGN(len);
                    144:                                h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
                    145:                                continue;
                    146:                        }
                    147: 
                    148:                        if(h->nlmsg_type == NLMSG_ERROR) {
                    149:                                struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
                    150:                                syslog(LOG_ERR, "NLMSG_ERROR %d : %s", err->error, strerror(-err->error));
                    151:                                goto error;
                    152:                        }
                    153:                        if(h->nlmsg_type == RTM_NEWROUTE) {
                    154:                                struct rtattr * rta;
                    155:                                int len = h->nlmsg_len;
                    156:                                len -= NLMSG_LENGTH(sizeof(struct rtmsg));
                    157:                                for(rta = RTM_RTA(NLMSG_DATA((h))); RTA_OK(rta, len); rta = RTA_NEXT(rta,len)) {
                    158:                                        unsigned char * data = RTA_DATA(rta);
                    159:                                        if(rta->rta_type == RTA_PREFSRC) {
                    160:                                                if(src_len && src) {
                    161:                                                        if(*src_len < RTA_PAYLOAD(rta)) {
                    162:                                                                syslog(LOG_WARNING, "cannot copy src: %u<%lu",
                    163:                                                                       (unsigned)*src_len, (unsigned long)RTA_PAYLOAD(rta));
                    164:                                                                goto error;
                    165:                                                        }
                    166:                                                        *src_len = RTA_PAYLOAD(rta);
                    167:                                                        memcpy(src, data, RTA_PAYLOAD(rta));
                    168:                                                }
                    169:                                        } else if(rta->rta_type == RTA_OIF) {
                    170:                                                if(index)
                    171:                                                        memcpy(index, data, sizeof(int));
                    172:                                        }
                    173:                                }
                    174:                                close(fd);
                    175:                                return 0;
                    176:                        }
                    177:                        status -= NLMSG_ALIGN(len);
                    178:                        h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
                    179:                }
                    180:        }
                    181:        syslog(LOG_WARNING, "get_src_for_route_to() : src not found");
                    182: error:
                    183:        if(fd >= 0)
                    184:                close(fd);
                    185:        return -1;
                    186: #else /* __linux__ */
                    187:        int found = 0;
                    188:        int s;
                    189:        int l, i;
                    190:        char * p;
                    191:        struct sockaddr * sa;
                    192:        struct {
                    193:          struct rt_msghdr m_rtm;
                    194:          char       m_space[512];
                    195:        } m_rtmsg;
                    196: #define rtm m_rtmsg.m_rtm
                    197: 
                    198:        if(dst == NULL)
                    199:                return -1;
                    200: #ifdef __APPLE__
                    201:        if(dst->sa_family == AF_INET6) {
                    202:                syslog(LOG_ERR, "Sorry, get_src_for_route_to() is known to fail with IPV6 on OS X...");
                    203:                return -1;
                    204:        }
                    205: #endif
                    206:        s = socket(PF_ROUTE, SOCK_RAW, dst->sa_family);
                    207:        if(s < 0) {
                    208:                syslog(LOG_ERR, "socket(PF_ROUTE) failed : %m");
                    209:                return -1;
                    210:        }
                    211:        memset(&rtm, 0, sizeof(rtm));
                    212:        rtm.rtm_type = RTM_GET;
                    213:        rtm.rtm_flags = RTF_UP;
                    214:        rtm.rtm_version = RTM_VERSION;
                    215:        rtm.rtm_seq = 1;
                    216:        rtm.rtm_addrs = RTA_DST;        /* destination address */
                    217:        memcpy(m_rtmsg.m_space, dst, sizeof(struct sockaddr));
                    218:        rtm.rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr);
                    219:        if(write(s, &m_rtmsg, rtm.rtm_msglen) < 0) {
                    220:                syslog(LOG_ERR, "write: %m");
                    221:                close(s);
                    222:                return -1;
                    223:        }
                    224: 
                    225:        do {
                    226:                l = read(s, &m_rtmsg, sizeof(m_rtmsg));
                    227:                if(l<0) {
                    228:                        syslog(LOG_ERR, "read: %m");
                    229:                        close(s);
                    230:                        return -1;
                    231:                }
                    232:                syslog(LOG_DEBUG, "read l=%d seq=%d pid=%d",
                    233:                       l, rtm.rtm_seq, rtm.rtm_pid);
                    234:        } while(l > 0 && (rtm.rtm_pid != getpid() || rtm.rtm_seq != 1));
                    235:        close(s);
                    236:        p = m_rtmsg.m_space;
                    237:        if(rtm.rtm_addrs) {
                    238:                for(i=1; i<0x8000; i <<= 1) {
                    239:                        if(i & rtm.rtm_addrs) {
                    240:                                char tmp[256] = { 0 };
                    241:                                sa = (struct sockaddr *)p;
                    242:                                sockaddr_to_string(sa, tmp, sizeof(tmp));
                    243:                                syslog(LOG_DEBUG, "type=%d sa_len=%d sa_family=%d %s",
                    244:                                       i, SA_LEN(sa), sa->sa_family, tmp);
                    245:                                if((i == RTA_DST || i == RTA_GATEWAY) &&
                    246:                                   (src_len && src)) {
                    247:                                        size_t len = 0;
                    248:                                        void * paddr = NULL;
                    249:                                        if(sa->sa_family == AF_INET) {
                    250:                                                paddr = &((struct sockaddr_in *)sa)->sin_addr;
                    251:                                                len = sizeof(struct in_addr);
                    252:                                        } else if(sa->sa_family == AF_INET6) {
                    253:                                                paddr = &((struct sockaddr_in6 *)sa)->sin6_addr;
                    254:                                                len = sizeof(struct in6_addr);
                    255:                                        }
                    256:                                        if(paddr) {
                    257:                                                if(*src_len < len) {
                    258:                                                        syslog(LOG_WARNING, "cannot copy src. %u<%u",
                    259:                                                               (unsigned)*src_len, (unsigned)len);
                    260:                                                        return -1;
                    261:                                                }
                    262:                                                memcpy(src, paddr, len);
                    263:                                                *src_len = len;
                    264:                                                found = 1;
                    265:                                        }
                    266:                                }
                    267: #ifdef AF_LINK
                    268:                                if(sa->sa_family == AF_LINK) {
                    269:                                        struct sockaddr_dl * sdl = (struct sockaddr_dl *)sa;
                    270:                                        if(index)
                    271:                                                *index = sdl->sdl_index;
                    272:                                }
                    273: #endif
                    274:                                p += SA_LEN(sa);
                    275:                        }
                    276:                }
                    277:        }
                    278:        return found ? 0 : -1;
                    279: #endif /* __linux__ */
                    280: }
                    281: 
                    282: #endif /* ENABLE_IPV6 */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>