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