Annotation of embedaddon/pimd/netlink.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Fred Griffoul <griffoul@ccrle.nec.de> sent me this file to use
! 3: * when compiling pimd under Linux.
! 4: *
! 5: * There was no copyright message or author name, so I assume he was the
! 6: * author, and deserves the copyright/credit for it:
! 7: *
! 8: * COPYRIGHT/AUTHORSHIP by Fred Griffoul <griffoul@ccrle.nec.de>
! 9: * (until proven otherwise).
! 10: */
! 11:
! 12: #include <sys/param.h>
! 13: #include <sys/file.h>
! 14: #include <sys/socket.h>
! 15: #include <netdb.h>
! 16: #include <stdlib.h>
! 17: #include <strings.h>
! 18: #include <paths.h>
! 19: #include "defs.h"
! 20:
! 21: #include <linux/rtnetlink.h>
! 22:
! 23: int routing_socket = -1;
! 24: static uint32_t pid; /* pid_t, but /usr/include/linux/netlink.h says __u32 ... */
! 25: static uint32_t seq;
! 26:
! 27: static int getmsg(struct rtmsg *rtm, int msglen, struct rpfctl *rpf);
! 28:
! 29: static int addattr32(struct nlmsghdr *n, size_t maxlen, int type, uint32_t data)
! 30: {
! 31: int len = RTA_LENGTH(4);
! 32: struct rtattr *rta;
! 33:
! 34: if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
! 35: return -1;
! 36:
! 37: rta = (struct rtattr *)(((char *)n) + NLMSG_ALIGN(n->nlmsg_len));
! 38: rta->rta_type = type;
! 39: rta->rta_len = len;
! 40: memcpy(RTA_DATA(rta), &data, 4);
! 41: n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
! 42:
! 43: return 0;
! 44: }
! 45:
! 46: static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
! 47: {
! 48: while (RTA_OK(rta, len)) {
! 49: if (rta->rta_type <= max)
! 50: tb[rta->rta_type] = rta;
! 51: rta = RTA_NEXT(rta, len);
! 52: }
! 53:
! 54: if (len)
! 55: logit(LOG_WARNING, 0, "NETLINK: Deficit in rtattr %d", len);
! 56:
! 57: return 0;
! 58: }
! 59:
! 60: /* open and initialize the routing socket */
! 61: int init_routesock(void)
! 62: {
! 63: socklen_t addr_len;
! 64: struct sockaddr_nl local;
! 65:
! 66: routing_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
! 67: if (routing_socket < 0) {
! 68: logit(LOG_ERR, errno, "Failed creating netlink socket");
! 69: return -1;
! 70: }
! 71:
! 72: memset(&local, 0, sizeof(local));
! 73: local.nl_family = AF_NETLINK;
! 74: local.nl_groups = 0;
! 75: if (bind(routing_socket, (struct sockaddr *)&local, sizeof(local)) < 0) {
! 76: logit(LOG_ERR, errno, "Failed binding to netlink socket");
! 77: return -1;
! 78: }
! 79:
! 80: addr_len = sizeof(local);
! 81: if (getsockname(routing_socket, (struct sockaddr *)&local, &addr_len) < 0) {
! 82: logit(LOG_ERR, errno, "Failed netlink getsockname");
! 83: return -1;
! 84: }
! 85:
! 86: if (addr_len != sizeof(local)) {
! 87: logit(LOG_ERR, 0, "Invalid netlink addr len.");
! 88: return -1;
! 89: }
! 90:
! 91: if (local.nl_family != AF_NETLINK) {
! 92: logit(LOG_ERR, 0, "Invalid netlink addr family.");
! 93: return -1;
! 94: }
! 95:
! 96: pid = local.nl_pid;
! 97: seq = time(NULL);
! 98:
! 99: return 0;
! 100: }
! 101:
! 102: /* get the rpf neighbor info */
! 103: int k_req_incoming(uint32_t source, struct rpfctl *rpf)
! 104: {
! 105: int l, rlen;
! 106: char buf[512];
! 107: struct nlmsghdr *n = (struct nlmsghdr *)buf;
! 108: struct rtmsg *r = NLMSG_DATA(n);
! 109: struct sockaddr_nl addr;
! 110:
! 111: rpf->source.s_addr = source;
! 112: rpf->iif = ALL_VIFS;
! 113: rpf->rpfneighbor.s_addr = 0;
! 114:
! 115: n->nlmsg_type = RTM_GETROUTE;
! 116: n->nlmsg_flags = NLM_F_REQUEST;
! 117: n->nlmsg_len = NLMSG_LENGTH(sizeof(*r));
! 118: n->nlmsg_pid = pid;
! 119: n->nlmsg_seq = ++seq;
! 120:
! 121: memset(r, 0, sizeof(*r));
! 122: r->rtm_family = AF_INET;
! 123: r->rtm_dst_len = 32;
! 124: addattr32(n, sizeof(buf), RTA_DST, rpf->source.s_addr);
! 125: #ifdef CONFIG_RTNL_OLD_IFINFO
! 126: r->rtm_optlen = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
! 127: #endif
! 128: addr.nl_family = AF_NETLINK;
! 129: addr.nl_groups = 0;
! 130: addr.nl_pid = 0;
! 131:
! 132: if (!IN_LINK_LOCAL_RANGE(rpf->source.s_addr)) {
! 133: IF_DEBUG(DEBUG_RPF)
! 134: logit(LOG_DEBUG, 0, "NETLINK: ask path to %s", inet_fmt(rpf->source.s_addr, s1, sizeof(s1)));
! 135: }
! 136:
! 137: while ((rlen = sendto(routing_socket, buf, n->nlmsg_len, 0, (struct sockaddr *)&addr, sizeof(addr))) < 0) {
! 138: if (errno == EINTR)
! 139: continue; /* Received signal, retry syscall. */
! 140:
! 141: logit(LOG_WARNING, errno, "Error writing to routing socket");
! 142: return FALSE;
! 143: }
! 144:
! 145: do {
! 146: socklen_t alen = sizeof(addr);
! 147:
! 148: l = recvfrom(routing_socket, buf, sizeof(buf), 0, (struct sockaddr *)&addr, &alen);
! 149: if (l < 0) {
! 150: if (errno == EINTR)
! 151: continue; /* Received signal, retry syscall. */
! 152:
! 153: logit(LOG_WARNING, errno, "Error writing to routing socket");
! 154: return FALSE;
! 155: }
! 156: } while (n->nlmsg_seq != seq || n->nlmsg_pid != pid);
! 157:
! 158: if (n->nlmsg_type != RTM_NEWROUTE) {
! 159: if (!IN_LINK_LOCAL_RANGE(rpf->source.s_addr)) {
! 160: if (n->nlmsg_type != NLMSG_ERROR)
! 161: logit(LOG_WARNING, 0, "netlink: wrong answer type %d", n->nlmsg_type);
! 162: else
! 163: logit(LOG_WARNING, -(*(int*)NLMSG_DATA(n)), "netlink get_route");
! 164: }
! 165:
! 166: return FALSE;
! 167: }
! 168:
! 169: return getmsg(NLMSG_DATA(n), l - sizeof(*n), rpf);
! 170: }
! 171:
! 172: static int getmsg(struct rtmsg *rtm, int msglen, struct rpfctl *rpf)
! 173: {
! 174: int ifindex;
! 175: vifi_t vifi;
! 176: struct uvif *v;
! 177: struct rtattr *rta[RTA_MAX + 1];
! 178:
! 179: if (!rpf) {
! 180: logit(LOG_WARNING, 0, "Missing rpf pointer to netlink.c:getmsg()!");
! 181: return FALSE;
! 182: }
! 183:
! 184: rpf->iif = NO_VIF;
! 185: rpf->rpfneighbor.s_addr = INADDR_ANY;
! 186:
! 187: if (rtm->rtm_type == RTN_LOCAL) {
! 188: IF_DEBUG(DEBUG_RPF)
! 189: logit(LOG_DEBUG, 0, "NETLINK: local address");
! 190:
! 191: if ((rpf->iif = local_address(rpf->source.s_addr)) != MAXVIFS) {
! 192: rpf->rpfneighbor.s_addr = rpf->source.s_addr;
! 193:
! 194: return TRUE;
! 195: }
! 196:
! 197: return FALSE;
! 198: }
! 199:
! 200: if (rtm->rtm_type != RTN_UNICAST) {
! 201: IF_DEBUG(DEBUG_RPF)
! 202: logit(LOG_DEBUG, 0, "NETLINK: route type is %d", rtm->rtm_type);
! 203: return FALSE;
! 204: }
! 205:
! 206: memset(rta, 0, sizeof(rta));
! 207: parse_rtattr(rta, RTA_MAX, RTM_RTA(rtm), msglen - sizeof(*rtm));
! 208:
! 209: if (!rta[RTA_OIF]) {
! 210: logit(LOG_WARNING, 0, "NETLINK: no outbound interface");
! 211: return FALSE;
! 212: }
! 213:
! 214: /* Get ifindex of outbound interface */
! 215: ifindex = *(int *)RTA_DATA(rta[RTA_OIF]);
! 216:
! 217: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
! 218: if (v->uv_ifindex == ifindex)
! 219: break;
! 220: }
! 221:
! 222: if (vifi >= numvifs) {
! 223: logit(LOG_WARNING, 0, "NETLINK: ifindex=%d, but no vif", ifindex);
! 224: return FALSE;
! 225: }
! 226:
! 227: /* Found inbound interface in vifi */
! 228: rpf->iif = vifi;
! 229:
! 230: IF_DEBUG(DEBUG_RPF)
! 231: logit(LOG_DEBUG, 0, "NETLINK: vif %d, ifindex=%d", vifi, ifindex);
! 232:
! 233: if (rta[RTA_GATEWAY]) {
! 234: uint32_t gw = *(uint32_t *)RTA_DATA(rta[RTA_GATEWAY]);
! 235:
! 236: IF_DEBUG(DEBUG_RPF)
! 237: logit(LOG_DEBUG, 0, "NETLINK: gateway is %s", inet_fmt(gw, s1, sizeof(s1)));
! 238: rpf->rpfneighbor.s_addr = gw;
! 239: } else {
! 240: rpf->rpfneighbor.s_addr = rpf->source.s_addr;
! 241: }
! 242:
! 243: return TRUE;
! 244: }
! 245:
! 246: /**
! 247: * Local Variables:
! 248: * version-control: t
! 249: * indent-tabs-mode: t
! 250: * c-file-style: "ellemtel"
! 251: * c-basic-offset: 4
! 252: * End:
! 253: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>