/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_cmd_ip_rule.c,v $ $Revision: 1.2.40.3 $ * $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_cmd_ip_rule.c,v $ * $Author: hxie $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifdef IPCOM_KERNEL #undef IPCOM_KERNEL #endif #include "ipnet_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include "ipnet.h" #include "ipnet_cmd.h" #include "ipnet_ctrl.h" #include "ipnet_h.h" #include "ipnet_sysctl.h" #include "ipnet_cmd_ip.h" #ifdef IPNET_USE_NETLINK /* **************************************************************************** * 4 DEFINES **************************************************************************** */ enum { IPNET_IP_RULE_MAIN_HELP, IPNET_IP_RULE_MAIN_LIST, IPNET_IP_RULE_MAIN_FLUSH, IPNET_IP_RULE_MAIN_ADD, IPNET_IP_RULE_MAIN_DEL, IPNET_IP_RULE_MAIN_MONITOR }; enum { IPNET_IP_RULE_ATTRIBUTE_NOT, IPNET_IP_RULE_ATTRIBUTE_FROM, IPNET_IP_RULE_ATTRIBUTE_TO, IPNET_IP_RULE_ATTRIBUTE_PREFERENCE, IPNET_IP_RULE_ATTRIBUTE_TABLE, IPNET_IP_RULE_ATTRIBUTE_IIF, IPNET_IP_RULE_ATTRIBUTE_PROHIBIT, IPNET_IP_RULE_ATTRIBUTE_UNREACHABLE, IPNET_IP_RULE_ATTRIBUTE_REJECT, IPNET_IP_RULE_ATTRIBUTE_SRCLOOKUP }; /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ static Ipcom_cmd_int_str_map ipnet_ip_rule_main[] = { { IPNET_IP_RULE_MAIN_HELP, "help" }, { IPNET_IP_RULE_MAIN_LIST, "show" }, { IPNET_IP_RULE_MAIN_LIST, "list" }, { IPNET_IP_RULE_MAIN_LIST, "lst" }, { IPNET_IP_RULE_MAIN_FLUSH, "flush" }, { IPNET_IP_RULE_MAIN_ADD, "add" }, { IPNET_IP_RULE_MAIN_DEL, "delete" }, { IPNET_IP_RULE_MAIN_DEL, "del" }, { IPNET_IP_RULE_MAIN_MONITOR, "monitor" }, { -1, IP_NULL }, }; static Ipcom_cmd_int_str_map ipnet_ip_rule_attributes[] = { { IPNET_IP_RULE_ATTRIBUTE_NOT, "not" }, { IPNET_IP_RULE_ATTRIBUTE_FROM, "from" }, { IPNET_IP_RULE_ATTRIBUTE_TO, "to" }, { IPNET_IP_RULE_ATTRIBUTE_PREFERENCE, "pref" }, { IPNET_IP_RULE_ATTRIBUTE_PREFERENCE, "prio" }, { IPNET_IP_RULE_ATTRIBUTE_PREFERENCE, "priority" }, { IPNET_IP_RULE_ATTRIBUTE_PREFERENCE, "preference" }, { IPNET_IP_RULE_ATTRIBUTE_TABLE, "table" }, { IPNET_IP_RULE_ATTRIBUTE_IIF, "iif" }, { IPNET_IP_RULE_ATTRIBUTE_PROHIBIT, "prohibit" }, { IPNET_IP_RULE_ATTRIBUTE_UNREACHABLE, "unreachable" }, { IPNET_IP_RULE_ATTRIBUTE_REJECT, "reject" }, { IPNET_IP_RULE_ATTRIBUTE_SRCLOOKUP, "src-lookup" }, { -1, IP_NULL }, }; /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC int ipnet_cmd_ip_rule_usage(Ipnet_ip_config_t *cfg, int ret) { ipnet_ip_stdio_printf(cfg, ""IP_LF); ipnet_ip_stdio_printf(cfg, "NAME"IP_LF); ipnet_ip_stdio_printf(cfg, " ip rule - Display and modify the IPNET routing rule states and configurations"IP_LF); ipnet_ip_stdio_printf(cfg, ""IP_LF); ipnet_ip_stdio_printf(cfg, "SYNOPSIS"IP_LF); ipnet_ip_stdio_printf(cfg, " ip rule "IP_LF); ipnet_ip_stdio_printf(cfg, " ip rule [not] [from ] [to ] [iif ]"IP_LF); ipnet_ip_stdio_printf(cfg, " [pref ] [table >] [prohibit] [reject] [unreachable] [src-lookup]"IP_LF); ipnet_ip_stdio_printf(cfg, " ip rule help"IP_LF); ipnet_ip_stdio_printf(cfg, " ip rule monitor"IP_LF); ipnet_ip_stdio_printf(cfg, ""IP_LF); ipnet_ip_stdio_printf(cfg, "DESCRIPTION"IP_LF); ipnet_ip_stdio_printf(cfg, " help Display usage information"IP_LF); ipnet_ip_stdio_printf(cfg, " list|flush List/Flush all rules"IP_LF); ipnet_ip_stdio_printf(cfg, " add|delete Add/Delete a rule based on the selectors"IP_LF); ipnet_ip_stdio_printf(cfg, " Selector Decription:"IP_LF); ipnet_ip_stdio_printf(cfg, " iif - The device the packet was received on"IP_LF); ipnet_ip_stdio_printf(cfg, " not - The meaning of the rule is inverted"IP_LF); ipnet_ip_stdio_printf(cfg, " to - The prefix matching the destination address"IP_LF); ipnet_ip_stdio_printf(cfg, " from - The prefix matching the source address"IP_LF); ipnet_ip_stdio_printf(cfg, " table - The table to try routing lookup in on success"IP_LF); ipnet_ip_stdio_printf(cfg, " prohibit - The rule generates a administratively prohibited result"IP_LF); ipnet_ip_stdio_printf(cfg, " unreachable - The rule generates a network unreachable result"IP_LF); ipnet_ip_stdio_printf(cfg, " reject - The rule generates a silent drop"IP_LF); ipnet_ip_stdio_printf(cfg, " pref - The preference of this rule"IP_LF); ipnet_ip_stdio_printf(cfg, " src-lookup - Do the routing lookup based on source address"IP_LF); return ret; } IP_STATIC Ip_u32 ipnet_cmd_ip_module_rule_get_table(Ipnet_ip_handle_msg_t *nlmsg) { struct Ip_fib_rule_hdr *fib = IP_NLMSG_DATA(nlmsg->hdr); if (nlmsg->rta[IP_FRA_TABLE]) return ipnet_ip_rta_u32(nlmsg->rta[IP_FRA_TABLE]); return fib->table; } IP_STATIC int ipnet_cmd_ip_module_rule_print(Ipnet_ip_config_t *cfg, Ipnet_ip_handle_msg_t *nlmsg) { char buf[128]; struct Ip_fib_rule_hdr *fib = IP_NLMSG_DATA(nlmsg->hdr); if (cfg->is_silent) return 0; ipnet_ip_parse_reply(nlmsg, IP_FRA_MAX, sizeof(*fib)); if (nlmsg->hdr->nlmsg_type == IP_RTM_DELRULE) ipnet_ip_stdio_printf(cfg, "Deleted "); ipcom_snprintf(buf, sizeof(buf), "%u:", IP_NULL != nlmsg->rta[IP_FRA_PRIORITY]? ipnet_ip_rta_u32(nlmsg->rta[IP_FRA_PRIORITY]) : 0); ipnet_ip_stdio_printf(cfg, "%08s", buf); if (IP_BIT_ISSET(fib->flags, IP_FIB_RULE_INVERT)) ipnet_ip_stdio_printf(cfg, " not"); ipnet_ip_stdio_printf(cfg, " from %s", ipnet_ip_format_host(fib->family, ipnet_ip_rta_data_safe(nlmsg->rta[IP_FRA_SRC]), fib->src_len, buf, sizeof(buf), "all")); ipnet_ip_stdio_printf(cfg, " to %s", ipnet_ip_format_host(fib->family, ipnet_ip_rta_data_safe(nlmsg->rta[IP_FRA_DST]), fib->dst_len, buf, sizeof(buf), "all")); if (IP_NULL != nlmsg->rta[IP_FRA_IFNAME]) ipnet_ip_stdio_printf(cfg, " iif %s", ipnet_ip_rta_str(nlmsg->rta[IP_FRA_IFNAME])); if (IP_FR_ACT_TO_TBL == fib->action) ipnet_ip_stdio_printf(cfg, " table %u", ipnet_cmd_ip_module_rule_get_table(nlmsg)); else if (IP_FR_ACT_BLACKHOLE == fib->action) ipnet_ip_stdio_printf(cfg, " reject"); else if (IP_FR_ACT_UNREACHABLE == fib->action) ipnet_ip_stdio_printf(cfg, " unreachable"); else if (IP_FR_ACT_PROHIBIT == fib->action) ipnet_ip_stdio_printf(cfg, " prohibit"); if (IP_BIT_ISSET(fib->flags, IP_FIB_RULE_FIND_SADDR)) ipnet_ip_stdio_printf(cfg, " src-lookup"); ipnet_ip_stdio_printf(cfg, IP_LF); return 0; } IP_STATIC Ip_ssize_t ipnet_cmd_ip_module_rule_list(Ipnet_ip_config_t *cfg) { Ip_ssize_t ret; Ipnet_ip_handle_msg_t *nlmsg; /* Dump the NETLINK information */ if (0 <= (ret = ipnet_ip_dump_netlink(cfg, cfg->handle, IP_RTM_GETRULE, cfg->family, cfg->core, IP_TRUE))) { for (nlmsg = IPCOM_LIST_FIRST(&cfg->handle->replies); IP_NULL != nlmsg; nlmsg = IPCOM_LIST_NEXT(&nlmsg->next)) ipnet_cmd_ip_module_rule_print(cfg, nlmsg); } else ipnet_ip_stdio_printf(cfg, "Unable to dump rule table, error = %d"IP_LF, (int)ret); return ret; } IP_STATIC Ip_ssize_t ipnet_cmd_ip_module_rule_flush(Ipnet_ip_config_t *cfg) { Ip_ssize_t ret; Ipnet_ip_handle_msg_t *nlmsg; /* Dump the NETLINK information */ if (0 <= (ret = ipnet_ip_dump_netlink(cfg, cfg->handle, IP_RTM_GETRULE, cfg->family, cfg->core, IP_TRUE))) { for (nlmsg = IPCOM_LIST_FIRST(&cfg->handle->replies); IP_NULL != nlmsg; nlmsg = IPCOM_LIST_NEXT(&nlmsg->next)) { if (nlmsg->hdr->nlmsg_type != IP_RTM_NEWRULE) continue; nlmsg->hdr->nlmsg_type = IP_RTM_DELRULE; nlmsg->hdr->nlmsg_flags = IP_NLM_F_REQUEST|IP_NLM_F_ACK; (void)ipnet_ip_request_netlink(cfg, cfg->handle, nlmsg->hdr, cfg->core, IP_TRUE); ipnet_cmd_ip_module_rule_print(cfg, nlmsg); } } return 0; } IP_STATIC Ip_ssize_t ipnet_cmd_ip_module_rule_modify(Ipnet_ip_config_t *cfg) { char *sarg; int arg; struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->tx[0]; struct Ip_fib_rule_hdr *fib; Ip_u32 uarg; ipcom_memset(nlh, 0, sizeof(*nlh)); nlh->nlmsg_len = IP_NLMSG_LENGTH(0); /* Start of the routing message */ fib = (struct Ip_fib_rule_hdr *)IP_NLMSG_DATA(nlh); ipcom_memset(fib, 0, sizeof(*fib)); fib->family = cfg->family; /* Move past the routing header */ nlh->nlmsg_len = IP_NLMSG_ALIGN(nlh->nlmsg_len) + sizeof(*fib); /* Time to go through the filter parameters */ while (IP_FALSE != ipnet_ip_cmd_param_str(&sarg, cfg)) { Ipnet_ip_prefix_t addr; if (IP_FALSE == ipnet_ip_str_to_key(&arg, ipnet_ip_rule_attributes, sarg)) return ipnet_cmd_ip_unknown_keyword(cfg, sarg); switch (arg) { case IPNET_IP_RULE_ATTRIBUTE_NOT: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "not", arg)) return -1; fib->flags |= IP_FIB_RULE_INVERT; break; case IPNET_IP_RULE_ATTRIBUTE_SRCLOOKUP: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "src-lookup", arg)) return -1; fib->flags |= IP_FIB_RULE_FIND_SADDR; break; case IPNET_IP_RULE_ATTRIBUTE_FROM: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "from ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "from "); if (IP_TRUE != ipnet_ip_str_to_prefix(fib->family, sarg, &addr)) return ipnet_cmd_ip_unknown_keyword(cfg, sarg); if (fib->family == IP_AF_UNSPEC) fib->family = addr.prefix_family; ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_FRA_SRC, &addr.prefix, addr.prefix_max/8); fib->src_len = addr.prefix_length; break; case IPNET_IP_RULE_ATTRIBUTE_TO: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "to ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "to "); if (IP_TRUE != ipnet_ip_str_to_prefix(fib->family, sarg, &addr)) return ipnet_cmd_ip_unknown_keyword(cfg, sarg); if (fib->family == IP_AF_UNSPEC) fib->family = addr.prefix_family; ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_FRA_DST, &addr.prefix, addr.prefix_max/8); fib->dst_len = addr.prefix_length; break; case IPNET_IP_RULE_ATTRIBUTE_PREFERENCE: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "pref ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL)) return ipnet_cmd_ip_requires_argument(cfg, "scope "); ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_FRA_PRIORITY, &uarg, sizeof(uarg)); break; case IPNET_IP_RULE_ATTRIBUTE_TABLE: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "table ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_uint(&uarg, cfg, IP_NULL)) return ipnet_cmd_ip_requires_argument(cfg, "table
"); ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_FRA_TABLE, &uarg, sizeof(uarg)); fib->table = (Ip_u16)uarg; fib->action = IP_FR_ACT_TO_TBL; break; case IPNET_IP_RULE_ATTRIBUTE_PROHIBIT: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "prohibit", arg)) return -1; fib->action = IP_FR_ACT_PROHIBIT; break; case IPNET_IP_RULE_ATTRIBUTE_UNREACHABLE: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "unreachable", arg)) return -1; fib->action = IP_FR_ACT_UNREACHABLE; break; case IPNET_IP_RULE_ATTRIBUTE_REJECT: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "reject", arg)) return -1; fib->action = IP_FR_ACT_BLACKHOLE; break; case IPNET_IP_RULE_ATTRIBUTE_IIF: if (IP_TRUE != ipnet_cmd_ip_check_mask(cfg, "iif ", arg)) return -1; if (IP_TRUE != ipnet_ip_cmd_param_str(&sarg, cfg)) return ipnet_cmd_ip_requires_argument(cfg, "iif "); ipcom_netlink_addattr_l(nlh, IPNET_IP_HANDLE_BUFFER, IP_FRA_IFNAME, sarg, ipcom_strlen(sarg) + 1); break; } } if (fib->action == IP_FR_ACT_UNSPEC) { ipnet_ip_stdio_printf(cfg, "One of \'table
\', \'reject\', \'prohibit\' or \'unreachable\' must be specified"IP_LF); return -1; } if (fib->family == IP_AF_UNSPEC) { if (cfg->family != IP_AF_UNSPEC) fib->family = cfg->family; else { #if defined(IPCOM_USE_INET) fib->family = IP_AF_INET; #else fib->family = IP_AF_INET6; #endif } } return 0; } IP_STATIC Ip_ssize_t ipnet_cmd_ip_module_rule_add(Ipnet_ip_config_t *cfg) { Ip_ssize_t ret = ipnet_cmd_ip_module_rule_modify(cfg); struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->tx[0]; if (0 <= ret) { nlh->nlmsg_flags = IP_NLM_F_CREATE|IP_NLM_F_EXCL|IP_NLM_F_REQUEST|IP_NLM_F_ACK; nlh->nlmsg_type = IP_RTM_NEWRULE; if (0 > (ret = ipnet_ip_request_netlink(cfg, cfg->handle, IP_NULL, cfg->core, IP_TRUE))) ipnet_ip_stdio_printf(cfg, "RTNETLINK answers: %s"IP_LF, ipcom_strerror(-(int)ret)); } return ret; } IP_STATIC Ip_ssize_t ipnet_cmd_ip_module_rule_delete(Ipnet_ip_config_t *cfg) { Ip_ssize_t ret = ipnet_cmd_ip_module_rule_modify(cfg); struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->tx[0]; if (0 <= ret) { nlh->nlmsg_type = IP_RTM_DELRULE; nlh->nlmsg_flags = IP_NLM_F_REQUEST|IP_NLM_F_ACK; if (0 > (ret = ipnet_ip_request_netlink(cfg, cfg->handle, IP_NULL, cfg->core, IP_TRUE))) ipnet_ip_stdio_printf(cfg, "RTNETLINK answers: %s"IP_LF, ipcom_strerror(-(int)ret)); } return ret; } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_GLOBAL Ip_ssize_t ipnet_cmd_ip_module_rule(Ipnet_ip_config_t *cfg) { int arg; char *sparam; cfg->handle = ipnet_ip_open_netlink(cfg, 0, IP_NETLINK_ROUTE); if (IP_NULL == cfg->handle) return -1; /* START */ /* Resolve the subcommand */ if (IP_TRUE != ipnet_ip_cmd_param_str(&sparam, cfg)) return ipnet_cmd_ip_rule_usage(cfg, -1); /* Resolve the module */ if (IP_FALSE == ipnet_ip_str_to_key(&arg, ipnet_ip_rule_main, sparam)) return ipnet_cmd_ip_unknown_keyword(cfg, sparam); else { ipnet_cmd_ip_clear_mask(cfg); switch (arg) { case IPNET_IP_RULE_MAIN_ADD: return ipnet_cmd_ip_module_rule_add(cfg); case IPNET_IP_RULE_MAIN_DEL: return ipnet_cmd_ip_module_rule_delete(cfg); case IPNET_IP_RULE_MAIN_LIST: return ipnet_cmd_ip_module_rule_list(cfg); case IPNET_IP_RULE_MAIN_FLUSH: return ipnet_cmd_ip_module_rule_flush(cfg); case IPNET_IP_RULE_MAIN_HELP: return ipnet_cmd_ip_rule_usage(cfg, 0); case IPNET_IP_RULE_MAIN_MONITOR: return ipnet_cmd_ip_module_monitor(cfg, IP_BIT_VAL(IPNET_IP_MODULE_RULE)); } } return 0; } IP_GLOBAL Ip_u32 ipnet_cmd_ip_module_rule_monitor_groups(Ipnet_ip_config_t *cfg) { if (cfg->family == IP_AF_INET) return IP_RTMGRP_IPV4_RULE; if (cfg->family == IP_AF_INET6) return IP_RTMGRP_IPV6_RULE; return IP_RTMGRP_IPV6_RULE|IP_RTMGRP_IPV4_RULE; } IP_GLOBAL Ip_bool ipnet_cmd_ip_module_rule_monitor(Ipnet_ip_config_t *cfg, Ipnet_ip_handle_msg_t *nlmsg) { if (nlmsg->hdr->nlmsg_type == IP_RTM_NEWRULE || nlmsg->hdr->nlmsg_type == IP_RTM_DELRULE) { ipnet_cmd_ip_module_rule_print(cfg, nlmsg); return IP_TRUE; } return IP_FALSE; } IP_GLOBAL Ip_ssize_t ipnet_cmd_ip_module_rule_flush_all(Ipnet_ip_config_t *cfg) { /**/ return ipnet_cmd_ip_module_rule_flush(cfg); } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ #endif /* IPNET_USE_NETLINK */ /* **************************************************************************** * END OF FILE **************************************************************************** */