Annotation of embedaddon/miniupnpd/minissdpd/getroute.c, revision 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>