File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpd / linux / getroute.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 00:32:35 2013 UTC (11 years, 3 months ago) by misho
Branches: elwix, MAIN
CVS tags: v1_8p0, v1_8, HEAD
1.8

    1: /* $Id: getroute.c,v 1.1.1.1 2013/07/22 00:32:35 misho 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>