Annotation of embedaddon/miniupnpd/linux/getroute.c, revision 1.1

1.1     ! misho       1: /* $Id: getroute.c,v 1.4 2013/02/06 10:50:04 nanard Exp $ */
        !             2: /* MiniUPnP project
        !             3:  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
        !             4:  * (c) 2006-2013 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: /*#include <linux/in_route.h>*/
        !            17: #include <linux/netlink.h>
        !            18: #include <linux/rtnetlink.h>
        !            19: #include <libnfnetlink/libnfnetlink.h>
        !            20: 
        !            21: #include "../getroute.h"
        !            22: #include "../upnputils.h"
        !            23: 
        !            24: int
        !            25: get_src_for_route_to(const struct sockaddr * dst,
        !            26:                      void * src, size_t * src_len,
        !            27:                      int * index)
        !            28: {
        !            29:        int fd = -1;
        !            30:        struct nlmsghdr *h;
        !            31:        int status;
        !            32:        struct {
        !            33:                struct nlmsghdr n;
        !            34:                struct rtmsg r;
        !            35:                char buf[1024];
        !            36:        } req;
        !            37:        struct sockaddr_nl nladdr;
        !            38:        struct iovec iov = {
        !            39:                .iov_base = (void*) &req.n,
        !            40:        };
        !            41:        struct msghdr msg = {
        !            42:                .msg_name = &nladdr,
        !            43:                .msg_namelen = sizeof(nladdr),
        !            44:                .msg_iov = &iov,
        !            45:                .msg_iovlen = 1,
        !            46:        };
        !            47:        const struct sockaddr_in * dst4;
        !            48:        const struct sockaddr_in6 * dst6;
        !            49: 
        !            50:        memset(&req, 0, sizeof(req));
        !            51:        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
        !            52:        req.n.nlmsg_flags = NLM_F_REQUEST;
        !            53:        req.n.nlmsg_type = RTM_GETROUTE;
        !            54:        req.r.rtm_family = dst->sa_family;
        !            55:        req.r.rtm_table = 0;
        !            56:        req.r.rtm_protocol = 0;
        !            57:        req.r.rtm_scope = 0;
        !            58:        req.r.rtm_type = 0;
        !            59:        req.r.rtm_src_len = 0;
        !            60:        req.r.rtm_dst_len = 0;
        !            61:        req.r.rtm_tos = 0;
        !            62: 
        !            63:        {
        !            64:                char dst_str[128];
        !            65:                sockaddr_to_string(dst, dst_str, sizeof(dst_str));
        !            66:                syslog(LOG_DEBUG, "get_src_for_route_to (%s)", dst_str);
        !            67:        }
        !            68:        /* add address */
        !            69:        if(dst->sa_family == AF_INET) {
        !            70:                dst4 = (const struct sockaddr_in *)dst;
        !            71:                nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst4->sin_addr, 4);
        !            72:                req.r.rtm_dst_len = 32;
        !            73:        } else {
        !            74:                dst6 = (const struct sockaddr_in6 *)dst;
        !            75:                nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst6->sin6_addr, 16);
        !            76:                req.r.rtm_dst_len = 128;
        !            77:        }
        !            78: 
        !            79:        fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
        !            80:        if (fd < 0) {
        !            81:                syslog(LOG_ERR, "socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) : %m");
        !            82:                return -1;
        !            83:        }
        !            84: 
        !            85:        memset(&nladdr, 0, sizeof(nladdr));
        !            86:        nladdr.nl_family = AF_NETLINK;
        !            87: 
        !            88:        req.n.nlmsg_seq = 1;
        !            89:        iov.iov_len = req.n.nlmsg_len;
        !            90: 
        !            91:        status = sendmsg(fd, &msg, 0);
        !            92: 
        !            93:        if (status < 0) {
        !            94:                syslog(LOG_ERR, "sendmsg(rtnetlink) : %m");
        !            95:                goto error;
        !            96:        }
        !            97: 
        !            98:        memset(&req, 0, sizeof(req));
        !            99: 
        !           100:        for(;;) {
        !           101:                iov.iov_len = sizeof(req);
        !           102:                status = recvmsg(fd, &msg, 0);
        !           103:                if(status < 0) {
        !           104:                        if (errno == EINTR || errno == EAGAIN)
        !           105:                                continue;
        !           106:                        syslog(LOG_ERR, "recvmsg(rtnetlink) %m");
        !           107:                        goto error;
        !           108:                }
        !           109:                if(status == 0) {
        !           110:                        syslog(LOG_ERR, "recvmsg(rtnetlink) EOF");
        !           111:                        goto error;
        !           112:                }
        !           113:                for (h = (struct nlmsghdr*)&req.n; status >= (int)sizeof(*h); ) {
        !           114:                        int len = h->nlmsg_len;
        !           115:                        int l = len - sizeof(*h);
        !           116: 
        !           117:                        if (l<0 || len>status) {
        !           118:                                if (msg.msg_flags & MSG_TRUNC) {
        !           119:                                        syslog(LOG_ERR, "Truncated message");
        !           120:                                }
        !           121:                                syslog(LOG_ERR, "malformed message: len=%d", len);
        !           122:                                goto error;
        !           123:                        }
        !           124: 
        !           125:                        if(nladdr.nl_pid != 0 || h->nlmsg_seq != 1/*seq*/) {
        !           126:                                syslog(LOG_ERR, "wrong seq = %d\n", h->nlmsg_seq);
        !           127:                                /* Don't forget to skip that message. */
        !           128:                                status -= NLMSG_ALIGN(len);
        !           129:                                h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
        !           130:                                continue;
        !           131:                        }
        !           132: 
        !           133:                        if(h->nlmsg_type == NLMSG_ERROR) {
        !           134:                                struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
        !           135:                                syslog(LOG_ERR, "NLMSG_ERROR %d : %s", err->error, strerror(-err->error));
        !           136:                                goto error;
        !           137:                        }
        !           138:                        if(h->nlmsg_type == RTM_NEWROUTE) {
        !           139:                                struct rtattr * rta;
        !           140:                                int len = h->nlmsg_len;
        !           141:                                len -= NLMSG_LENGTH(sizeof(struct rtmsg));
        !           142:                                for(rta = RTM_RTA(NLMSG_DATA((h))); RTA_OK(rta, len); rta = RTA_NEXT(rta,len)) {
        !           143:                                        unsigned char * data = RTA_DATA(rta);
        !           144:                                        if(rta->rta_type == RTA_PREFSRC) {
        !           145:                                                if(src_len && src) {
        !           146:                                                        if(*src_len < RTA_PAYLOAD(rta)) {
        !           147:                                                                syslog(LOG_WARNING, "cannot copy src: %u<%lu",
        !           148:                                                                       (unsigned)*src_len, RTA_PAYLOAD(rta));
        !           149:                                                                goto error;
        !           150:                                                        }
        !           151:                                                        *src_len = RTA_PAYLOAD(rta);
        !           152:                                                        memcpy(src, data, RTA_PAYLOAD(rta));
        !           153:                                                }
        !           154:                                        } else if(rta->rta_type == RTA_OIF) {
        !           155:                                                if(index)
        !           156:                                                        memcpy(index, data, sizeof(int));
        !           157:                                        }
        !           158:                                }
        !           159:                                close(fd);
        !           160:                                return 0;
        !           161:                        }
        !           162:                        status -= NLMSG_ALIGN(len);
        !           163:                        h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
        !           164:                }
        !           165:        }
        !           166:        syslog(LOG_WARNING, "get_src_for_route_to() : src not found");
        !           167: error:
        !           168:        if(fd >= 0)
        !           169:                close(fd);
        !           170:        return -1;
        !           171: }
        !           172: 

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