/* Helper for netlink */ /* * (C) 2014 by Holger Hans Peter Freyther * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ #include #include #include #include #include #include #include #include #include #define NLMSG_TAIL(nmsg) \ ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) /** * In case one binds to 0.0.0.0/INADDR_ANY and wants to know which source * address will be used when sending a message this function can be used. * It will ask the routing code of the kernel for the PREFSRC */ int source_for_dest(const struct in_addr *dest, struct in_addr *loc_source) { int fd, rc; struct rtmsg *r; struct rtattr *rta; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; memset(&req, 0, sizeof(req)); fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE); if (fd < 0) { perror("nl socket"); return -1; } /* Send a rtmsg and ask for a response */ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; req.n.nlmsg_type = RTM_GETROUTE; req.n.nlmsg_seq = 1; /* Prepare the routing request */ req.r.rtm_family = AF_INET; /* set the dest */ rta = NLMSG_TAIL(&req.n); rta->rta_type = RTA_DST; rta->rta_len = RTA_LENGTH(sizeof(*dest)); memcpy(RTA_DATA(rta), dest, sizeof(*dest)); /* update sizes for dest */ req.r.rtm_dst_len = sizeof(*dest) * 8; req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len) + RTA_ALIGN(rta->rta_len); rc = send(fd, &req, req.n.nlmsg_len, 0); if (rc != req.n.nlmsg_len) { perror("short write"); close(fd); return -2; } /* now receive a response and parse it */ rc = recv(fd, &req, sizeof(req), 0); if (rc <= 0) { perror("short read"); close(fd); return -3; } if (!NLMSG_OK(&req.n, rc) || req.n.nlmsg_type != RTM_NEWROUTE) { close(fd); return -4; } r = NLMSG_DATA(&req.n); rc -= NLMSG_LENGTH(sizeof(*r)); rta = RTM_RTA(r); while (RTA_OK(rta, rc)) { if (rta->rta_type != RTA_PREFSRC) { rta = RTA_NEXT(rta, rc); continue; } /* we are done */ memcpy(loc_source, RTA_DATA(rta), RTA_PAYLOAD(rta)); close(fd); return 0; } close(fd); return -5; }