/* add/remove iptable drop rule to VIP */ static void handle_iptable_rule_to_vip(ip_address_t *ipaddress, int cmd, char *ifname, void *unused) { char *argv[10]; unsigned int i = 0; int if_specifier = -1; char *addr_str; if (global_data->vrrp_iptables_inchain[0] == '\0') return; if (IP_IS6(ipaddress)) { handle_iptable_rule_to_NA(ipaddress, cmd, ifname); argv[i++] = "ip6tables"; } else { argv[i++] = "iptables"; } addr_str = ipaddresstos(NULL, ipaddress); argv[i++] = cmd ? "-A" : "-D"; argv[i++] = global_data->vrrp_iptables_inchain; argv[i++] = "-d"; argv[i++] = addr_str; if (IP_IS6(ipaddress) && IN6_IS_ADDR_LINKLOCAL(&ipaddress->u.sin6_addr)) { if_specifier = i; argv[i++] = "-i"; argv[i++] = ifname; } argv[i++] = "-j"; argv[i++] = "DROP"; argv[i] = NULL; if (fork_exec(argv) < 0) log_message(LOG_ERR, "Failed to %s iptable drop rule" " to vip %s", (cmd) ? "set" : "remove", addr_str); else ipaddress->iptable_rule_set = (cmd != IPADDRESS_DEL); if (global_data->vrrp_iptables_outchain[0] == '\0') return; argv[2] = global_data->vrrp_iptables_outchain ; argv[3] = "-s"; if (if_specifier >= 0) argv[if_specifier] = "-o"; if (fork_exec(argv) < 0) log_message(LOG_ERR, "Failed to %s iptable drop rule" " from vip %s", (cmd) ? "set" : "remove", addr_str); }
static int add_addr2rta(struct rtattr *rta, int maxlen, int type, ip_address_t *ip_address) { void *addr; int alen; if (!ip_address) return -1; addr = (IP_IS6(ip_address)) ? (void *) &ip_address->u.sin6_addr : (void *) &ip_address->u.sin.sin_addr; alen = (IP_IS6(ip_address)) ? sizeof(ip_address->u.sin6_addr) : sizeof(ip_address->u.sin.sin_addr); return rta_addattr_l(rta, maxlen, type, addr, alen); }
void address_print(FILE *file, void *data) { ip_address_t *ipaddr = data; char *broadcast = (char *) MALLOC(21); char *addr_str = (char *) MALLOC(41); if (IP_IS6(ipaddr)) { inet_ntop(AF_INET6, &ipaddr->u.sin6_addr, addr_str, 41); } else { inet_ntop(AF_INET, &ipaddr->u.sin.sin_addr, addr_str, 41); if (ipaddr->u.sin.sin_brd.s_addr) snprintf(broadcast, 20, " brd %s", inet_ntop2(ipaddr->u.sin.sin_brd.s_addr)); } fprintf(file, " %s/%d%s dev %s scope %s%s%s\n" , addr_str , ipaddr->ifa.ifa_prefixlen , broadcast , IF_NAME(ipaddr->ifp) , netlink_scope_n2a(ipaddr->ifa.ifa_scope) , ipaddr->label ? " label " : "" , ipaddr->label ? ipaddr->label : ""); FREE(broadcast); FREE(addr_str); }
static void address_print(FILE *file, void *data) { ip_address_t *ipaddr = data; char broadcast[INET_ADDRSTRLEN + 5] = ""; /* allow for " brd " */ char addr_str[INET6_ADDRSTRLEN] = ""; if (IP_IS6(ipaddr)) { inet_ntop(AF_INET6, &ipaddr->u.sin6_addr, addr_str, sizeof(addr_str)); } else { inet_ntop(AF_INET, &ipaddr->u.sin.sin_addr, addr_str, sizeof(addr_str)); if (ipaddr->u.sin.sin_brd.s_addr) snprintf(broadcast, sizeof(broadcast) - 1, " brd %s", inet_ntop2(ipaddr->u.sin.sin_brd.s_addr)); } fprintf(file, " %s/%d%s dev %s%s%s%s%s\n" , addr_str , ipaddr->ifa.ifa_prefixlen , broadcast , IF_NAME(ipaddr->ifp) , IP_IS4(ipaddr) ? " scope " : "" , IP_IS4(ipaddr) ? netlink_scope_n2a(ipaddr->ifa.ifa_scope) : "" , ipaddr->label ? " label " : "" , ipaddr->label ? ipaddr->label : ""); }
char * ipaddresstos(char *buf, ip_address_t *ipaddress) { static char addr_str[INET6_ADDRSTRLEN]; if (!buf) buf = addr_str; if (IP_IS6(ipaddress)) { inet_ntop(AF_INET6, &ipaddress->u.sin6_addr, buf, INET6_ADDRSTRLEN); } else { inet_ntop(AF_INET, &ipaddress->u.sin.sin_addr, buf, INET_ADDRSTRLEN); } return buf; }
void handle_iptable_rule_to_vip(ip_address_t *ipaddress, int cmd, char *ifname, struct ipt_handle *h) { char *my_ifname = NULL; if (!use_iptables) return; if (global_data->vrrp_iptables_inchain[0] == '\0') return; #ifdef _HAVE_LIBIPSET_ if (global_data->using_ipsets) { if (!h->session) h->session = ipset_session_start(); ipset_entry(h->session, cmd, ipaddress, ifname); ipaddress->iptable_rule_set = (cmd != IPADDRESS_DEL); return; } #endif if (IP_IS6(ipaddress)) { if (IN6_IS_ADDR_LINKLOCAL(&ipaddress->u.sin6_addr)) my_ifname = ifname; handle_iptable_rule_to_NA(ipaddress, cmd, my_ifname, h); } iptables_entry(h, global_data->vrrp_iptables_inchain, -1, XTC_LABEL_DROP, NULL, ipaddress, my_ifname, NULL, IPPROTO_NONE, 0, cmd); ipaddress->iptable_rule_set = (cmd != IPADDRESS_DEL); if (global_data->vrrp_iptables_outchain[0] == '\0') return; iptables_entry(h, global_data->vrrp_iptables_outchain, -1, XTC_LABEL_DROP, ipaddress, NULL, NULL, my_ifname, IPPROTO_NONE, 0, cmd); }
void dump_ipaddress(void *if_data) { ip_address_t *ipaddr = if_data; char broadcast[INET_ADDRSTRLEN + 5] = ""; if (!IP_IS6(ipaddr) && ipaddr->u.sin.sin_brd.s_addr) { snprintf(broadcast, 21, " brd %s", inet_ntop2(ipaddr->u.sin.sin_brd.s_addr)); } log_message(LOG_INFO, " %s/%d%s dev %s scope %s%s%s" , ipaddresstos(NULL, ipaddr) , ipaddr->ifa.ifa_prefixlen , broadcast , IF_NAME(ipaddr->ifp) , get_rttables_scope(ipaddr->ifa.ifa_scope) , ipaddr->label ? " label " : "" , ipaddr->label ? ipaddr->label : ""); }
/* Utility functions */ static int add_addr2req(struct nlmsghdr *n, int maxlen, int type, ip_address_t *ip_address) { void *addr; int alen; if (!ip_address) return -1; if (IP_IS6(ip_address)) { addr = (void *) &ip_address->u.sin6_addr; alen = sizeof(ip_address->u.sin6_addr); } else { addr = (void *) &ip_address->u.sin.sin_addr; alen = sizeof(ip_address->u.sin.sin_addr); } return addattr_l(n, maxlen, type, addr, alen); }
static int add_addr_fam2req(struct nlmsghdr *n, int maxlen, int type, ip_address_t *ip_address) { void *addr; int alen; uint16_t family; if (!ip_address) return -1; if (IP_IS6(ip_address)) { addr = (void *)&ip_address->u.sin6_addr; alen = sizeof(ip_address->u.sin6_addr); } else { addr = (void *)&ip_address->u.sin.sin_addr; alen = sizeof(ip_address->u.sin.sin_addr); } family = ip_address->ifa.ifa_family; return addattr_l2(n, maxlen, type, &family, sizeof(family), addr, alen); }
/* Add/Delete IP address to a specific interface_t */ int netlink_ipaddress(ip_address_t *ipaddress, int cmd) { struct ifa_cacheinfo cinfo; int status = 1; struct { struct nlmsghdr n; struct ifaddrmsg ifa; char buf[256]; } req; memset(&req, 0, sizeof (req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifaddrmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = (cmd == IPADDRESS_DEL) ? RTM_DELADDR : RTM_NEWADDR; req.ifa = ipaddress->ifa; if (IP_IS6(ipaddress)) { if (cmd == IPADDRESS_ADD) { /* Mark IPv6 address as deprecated (rfc3484) in order to prevent * using VRRP VIP as source address in healthchecking use cases. */ if (ipaddress->ifa.ifa_prefixlen == 128) { memset(&cinfo, 0, sizeof(cinfo)); cinfo.ifa_prefered = 0; cinfo.ifa_valid = INFINITY_LIFE_TIME; log_message(LOG_INFO, "%s has a prefix length of 128, setting " "preferred_lft to 0", ipaddresstos(NULL, ipaddress)); addattr_l(&req.n, sizeof(req), IFA_CACHEINFO, &cinfo, sizeof(cinfo)); } /* Disable, per VIP, Duplicate Address Detection algorithm (DAD). * Using the nodad flag has the following benefits: * * (1) The address becomes immediately usable after they're * configured. * (2) In the case of a temporary layer-2 / split-brain problem * we can avoid that the active VIP transitions into the * dadfailed phase and stays there forever - leaving us * without service. HA/VRRP setups have their own "DAD"-like * functionality, so it's not really needed from the IPv6 stack. */ #ifdef IFA_F_NODAD /* Since Linux 2.6.19 */ req.ifa.ifa_flags |= IFA_F_NODAD; #endif } addattr_l(&req.n, sizeof(req), IFA_LOCAL, &ipaddress->u.sin6_addr, sizeof(ipaddress->u.sin6_addr)); } else { addattr_l(&req.n, sizeof(req), IFA_LOCAL, &ipaddress->u.sin.sin_addr, sizeof(ipaddress->u.sin.sin_addr)); if (cmd == IPADDRESS_ADD) { if (ipaddress->u.sin.sin_brd.s_addr) addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &ipaddress->u.sin.sin_brd, sizeof(ipaddress->u.sin.sin_brd)); } else { /* IPADDRESS_DEL */ addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &ipaddress->u.sin.sin_addr, sizeof(ipaddress->u.sin.sin_addr)); } } if (cmd == IPADDRESS_ADD) if (ipaddress->label) addattr_l(&req.n, sizeof (req), IFA_LABEL, ipaddress->label, strlen(ipaddress->label) + 1); if (netlink_talk(&nl_cmd, &req.n) < 0) status = -1; return status; }