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>