/* Add/Delete IP rule to/from a specific IP/network */ int netlink_rule(ip_rule_t *iprule, int cmd) { int status = 1; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; memset(&req, 0, sizeof (req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; req.n.nlmsg_type = cmd ? RTM_NEWRULE : RTM_DELRULE; req.r.rtm_family = IP_FAMILY(iprule->addr); if (iprule->table < 256) req.r.rtm_table = iprule->table ? iprule->table : RT_TABLE_MAIN; else { req.r.rtm_table = RT_TABLE_UNSPEC; addattr32(&req.n, sizeof(req), FRA_TABLE, iprule->table); } req.r.rtm_type = RTN_UNSPEC; req.r.rtm_scope = RT_SCOPE_UNIVERSE; req.r.rtm_flags = 0; if (cmd) { req.r.rtm_protocol = RTPROT_BOOT; req.r.rtm_type = RTN_UNICAST; } /* Set rule entry */ if (iprule->dir == VRRP_RULE_FROM) { req.r.rtm_src_len = iprule->mask; add_addr2req(&req.n, sizeof(req), FRA_SRC, iprule->addr); } else if (iprule->dir == VRRP_RULE_TO) { req.r.rtm_dst_len = iprule->mask; add_addr2req(&req.n, sizeof(req), FRA_DST, iprule->addr); } if (netlink_talk(&nl_cmd, &req.n) < 0) status = -1; return status; }
static void vrrp_vip_handler(vector_t *strvec) { vrrp_t *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp); char *buf; char *str = NULL; vector_t *vec = NULL; int address_family; buf = (char *) MALLOC(MAXBUF); while (read_line(buf, MAXBUF)) { address_family = AF_UNSPEC; vec = alloc_strvec(buf); if (vec) { str = vector_slot(vec, 0); if (!strcmp(str, EOB)) { free_strvec(vec); break; } if (vector_size(vec)) { alloc_vrrp_vip(vec); if (!LIST_ISEMPTY(vrrp->vip)) address_family = IP_FAMILY((ip_address_t*)LIST_TAIL_DATA(vrrp->vip)); } if (address_family != AF_UNSPEC) { if (vrrp->family == AF_UNSPEC) vrrp->family = address_family; else if (address_family != vrrp->family) { log_message(LOG_INFO, "(%s): address family must match VRRP instance [%s] - ignoring", vrrp->iname, buf); free_list_element(vrrp->vip, LIST_TAIL_DATA(vrrp->vip)); } } free_strvec(vec); } memset(buf, 0, MAXBUF); } FREE(buf); }
/* Add/Delete IP route to/from a specific interface */ static int netlink_route(ip_route_t *iproute, int cmd) { int status = 1; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; char buf[1024]; struct rtattr *rta = (void*)buf; struct rtnexthop *rtnh; memset(&req, 0, sizeof (req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; req.n.nlmsg_type = cmd ? RTM_NEWROUTE : RTM_DELROUTE; req.r.rtm_family = (iproute->dst) ? IP_FAMILY(iproute->dst) : (iproute->src) ? IP_FAMILY(iproute->src) : AF_INET; if (iproute->table < 256) req.r.rtm_table = iproute->table ? iproute->table : RT_TABLE_MAIN; else { req.r.rtm_table = RT_TABLE_UNSPEC; addattr32(&req.n, sizeof(req), RTA_TABLE, iproute->table); } req.r.rtm_scope = RT_SCOPE_NOWHERE; if (cmd == IPROUTE_ADD) { req.r.rtm_protocol = RTPROT_BOOT; req.r.rtm_scope = iproute->scope; req.r.rtm_type = RTN_UNICAST; } if (iproute->blackhole) req.r.rtm_type = RTN_BLACKHOLE; /* Set routing entry */ if (iproute->dst) { req.r.rtm_dst_len = iproute->dmask; add_addr2req(&req.n, sizeof(req), RTA_DST, iproute->dst); } if ((!iproute->blackhole) && (!iproute->gw2)) add_addr2req(&req.n, sizeof(req), RTA_GATEWAY, iproute->gw); if (iproute->gw && iproute->gw2) { rta->rta_type = RTA_MULTIPATH; rta->rta_len = RTA_LENGTH(0); rtnh = RTA_DATA(rta); #define MULTIPATH_ADD_GW(x) \ memset(rtnh, 0, sizeof(*rtnh)); \ rtnh->rtnh_len = sizeof(*rtnh); \ if (iproute->index) rtnh->rtnh_ifindex = iproute->index; \ rta->rta_len += rtnh->rtnh_len; \ add_addr2rta(rta, 1024, RTA_GATEWAY, x); \ rtnh->rtnh_len += sizeof(struct rtattr) + IP_SIZE(x); \ rtnh = RTNH_NEXT(rtnh); MULTIPATH_ADD_GW(iproute->gw); MULTIPATH_ADD_GW(iproute->gw2); addattr_l(&req.n, sizeof(req), RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta)); } if ((iproute->index) && (!iproute->gw2)) addattr32(&req.n, sizeof(req), RTA_OIF, iproute->index); if (iproute->src) add_addr2req(&req.n, sizeof(req), RTA_PREFSRC, iproute->src); if (iproute->metric) addattr32(&req.n, sizeof(req), RTA_PRIORITY, iproute->metric); /* This returns ESRCH if the address of via address doesn't exist */ /* ENETDOWN if dev p33p1.40 for example is down */ if (netlink_talk(&nl_cmd, &req.n) < 0) status = -1; return status; }