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>