static void route_print(FILE *file, void *data) { ip_route_t *route = data; fprintf(file, " "); if (route->blackhole) fprintf(file, "blackhole "); if (route->dst) fprintf(file, "%s/%d", ipaddresstos(NULL, route->dst), route->dmask); if (route->gw) fprintf(file, " gw %s", ipaddresstos(NULL, route->gw)); if (route->gw2) fprintf(file, " or gw %s", ipaddresstos(NULL, route->gw2)); if (route->src) fprintf(file, " src %s", ipaddresstos(NULL, route->src)); if (route->index) fprintf(file, " dev %s", IF_NAME(if_get_by_ifindex(route->index))); if (route->table) fprintf(file, " table %d", route->table); if (route->scope) fprintf(file, " scope %s", netlink_scope_n2a(route->scope)); if (route->metric) fprintf(file, " metric %d", route->metric); fprintf(file, "\n"); }
void dump_iproute(void *rt_data) { ip_route_t *route = rt_data; char *log_msg = MALLOC(1024); char *op = log_msg; if (route->blackhole) { strncat(log_msg, "blackhole ", 30); } if (route->dst) op += snprintf(op, log_msg + 1024 - op, "%s/%d", ipaddresstos(NULL, route->dst), route->dmask); if (route->gw) op += snprintf(op, log_msg + 1024 - op, " gw %s", ipaddresstos(NULL, route->gw)); if (route->gw2) op += snprintf(op, log_msg + 1024 - op, " or gw %s", ipaddresstos(NULL, route->gw2)); if (route->src) op += snprintf(op, log_msg + 1024 - op, " src %s", ipaddresstos(NULL, route->src)); if (route->index) op += snprintf(op, log_msg + 1024 - op, " dev %s", IF_NAME(if_get_by_ifindex(route->index))); if (route->table) op += snprintf(op, log_msg + 1024 - op, " table %d", route->table); if (route->scope) op += snprintf(op, log_msg + 1024 - op, " scope %s", netlink_scope_n2a(route->scope)); if (route->metric) op += snprintf(op, log_msg + 1024 - op, " metric %d", route->metric); log_message(LOG_INFO, " %s", log_msg); FREE(log_msg); }
void dump_iproute(void *rt_data) { ip_route_t *route = rt_data; char *log_msg = MALLOC(1024); char *tmp = MALLOC(INET6_ADDRSTRLEN + 30); char *tmp_str; if (route->blackhole) { strncat(log_msg, "blackhole ", 30); } if (route->dst) { tmp_str = ipaddresstos(route->dst); snprintf(tmp, INET6_ADDRSTRLEN + 30, "%s/%d", tmp_str, route->dmask); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); FREE(tmp_str); } if (route->gw) { tmp_str = ipaddresstos(route->gw); snprintf(tmp, INET6_ADDRSTRLEN + 30, " gw %s", tmp_str); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); FREE(tmp_str); } if (route->gw2) { tmp_str = ipaddresstos(route->gw2); snprintf(tmp, INET6_ADDRSTRLEN + 30, " or gw %s", tmp_str); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); FREE(tmp_str); } if (route->src) { tmp_str = ipaddresstos(route->src); snprintf(tmp, INET6_ADDRSTRLEN + 30, " src %s", tmp_str); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); FREE(tmp_str); } if (route->index) { snprintf(tmp, INET6_ADDRSTRLEN + 30, " dev %s", IF_NAME(if_get_by_ifindex(route->index))); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); } if (route->table) { snprintf(tmp, INET6_ADDRSTRLEN + 30, " table %d", route->table); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); } if (route->scope) { snprintf(tmp, INET6_ADDRSTRLEN + 30, " scope %s", netlink_scope_n2a(route->scope)); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); } if (route->metric) { snprintf(tmp, INET6_ADDRSTRLEN + 30, " metric %d", route->metric); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); } log_message(LOG_INFO, " %s", log_msg); FREE(tmp); FREE(log_msg); }
void route_print(FILE *file, void *data) { ip_route_t *route = data; char *msg = MALLOC(150); char *tmp = MALLOC(30); if (route->blackhole) { strncat(msg, "blackhole ", 30); } if (route->dst) { snprintf(tmp, 30, "%s/%d", ipaddresstos(route->dst), route->dmask); strncat(msg, tmp, 30); } if (route->gw) { snprintf(tmp, 30, " gw %s", ipaddresstos(route->gw)); strncat(msg, tmp, 30); } if (route->gw2) { snprintf(tmp, 30, " or gw %s", ipaddresstos(route->gw2)); strncat(msg, tmp, 30); } if (route->src) { snprintf(tmp, 30, " src %s", ipaddresstos(route->src)); strncat(msg, tmp, 30); } if (route->index) { snprintf(tmp, 30, " dev %s", IF_NAME(if_get_by_ifindex(route->index))); strncat(msg, tmp, 30); } if (route->table) { snprintf(tmp, 30, " table %d", route->table); strncat(msg, tmp, 30); } if (route->scope) { snprintf(tmp, 30, " scope %s", netlink_scope_n2a(route->scope)); strncat(msg, tmp, 30); } if (route->metric) { snprintf(tmp, 30, " metric %d", route->metric); strncat(msg, tmp, 30); } fprintf(file, " %s\n", msg); FREE(tmp); FREE(msg); }
void rule_print(FILE *file, void *data) { ip_rule_t *rule = data; char *msg = MALLOC(150); char *tmp = MALLOC(30); if (rule->dir) { snprintf(tmp, 30, "%s ", rule->dir); strncat(msg, tmp, 30); } if (rule->addr) { snprintf(tmp, 30, "%s", ipaddresstos(rule->addr)); strncat(msg, tmp, 30); } if (rule->table) { snprintf(tmp, 30, " table %d", rule->table); strncat(msg, tmp, 30); } fprintf(file, " %s\n", msg); FREE(tmp); FREE(msg); }
static size_t print_encap_ip6(char *op, size_t len, const encap_t* encap) { char *opn = op; opn += snprintf(opn, len - (opn - op), " encap ip6"); if (encap->flags & IPROUTE_BIT_ENCAP_ID) opn += snprintf(opn, len - (opn - op), " id %" PRIu64, encap->ip6.id); if (encap->ip.dst) opn += snprintf(opn, len - (opn - op), " dst %s", ipaddresstos(NULL, encap->ip6.dst)); if (encap->ip.src) opn += snprintf(opn, len - (opn - op), " src %s", ipaddresstos(NULL, encap->ip6.src)); if (encap->flags & IPROUTE_BIT_ENCAP_DSFIELD) opn += snprintf(opn, len - (opn - op), " tc %d", encap->ip6.tc); if (encap->flags & IPROUTE_BIT_ENCAP_HOPLIMIT) opn += snprintf(opn, len - (opn - op), " hoplimit %d", encap->ip6.hoplimit); if (encap->flags & IPROUTE_BIT_ENCAP_FLAGS) opn += snprintf(opn, len - (opn - op), " flags 0x%x", encap->ip6.flags); return opn - op; }
static size_t print_encap_ip(char *op, size_t len, const encap_t* encap) { char *opn = op; opn += snprintf(opn, len - (opn - op), " encap ip"); if (encap->flags & IPROUTE_BIT_ENCAP_ID) opn += snprintf(opn, len - (opn - op), " id %" PRIu64, encap->ip.id); if (encap->ip.dst) opn += snprintf(opn, len - (opn - op), " dst %s", ipaddresstos(NULL, encap->ip.dst)); if (encap->ip.src) opn += snprintf(opn, len - (opn - op), " src %s", ipaddresstos(NULL, encap->ip.src)); if (encap->flags & IPROUTE_BIT_ENCAP_DSFIELD) opn += snprintf(opn, len - (opn - op), " tos %d", encap->ip.tos); if (encap->flags & IPROUTE_BIT_ENCAP_TTL) opn += snprintf(opn, len - (opn - op), " ttl %d", encap->ip.ttl); if (encap->flags & IPROUTE_BIT_ENCAP_FLAGS) opn += snprintf(opn, len - (opn - op), " flags 0x%x", encap->ip.flags); return opn - op; }
/* 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 void rule_print(FILE *file, void *data) { ip_rule_t *rule = data; fprintf(file, " "); if (rule->dir) fprintf(file, "%s ", (rule->dir == VRRP_RULE_FROM) ? "from" : "to"); if (rule->addr) fprintf(file, "%s", ipaddresstos(NULL, rule->addr)); if (rule->table) fprintf(file, " table %d", rule->table); fprintf(file, "\n"); }
void dump_iprule(void *rule_data) { ip_rule_t *rule = rule_data; char *log_msg = MALLOC(1024); char *op = log_msg; if (rule->dir) op += snprintf(op, log_msg + 1024 - op, "%s ", (rule->dir == VRRP_RULE_FROM) ? "from" : "to"); if (rule->addr) op += snprintf(op, log_msg + 1024 - op, "%s/%d", ipaddresstos(NULL, rule->addr), rule->mask); if (rule->table) op += snprintf(op, log_msg + 1024 - op, " table %d", rule->table); log_message(LOG_INFO, " %s", log_msg); FREE(log_msg); }
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 : ""); }
/* 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; }
static void handle_iptable_rule_to_NA(ip_address_t *ipaddress, int cmd, char *ifname, bool force) { char *argv[14]; unsigned int i = 0; int if_specifier = -1; int type_specifier ; char *addr_str; if (global_data->vrrp_iptables_inchain[0] == '\0') return; addr_str = ipaddresstos(NULL, ipaddress); argv[i++] = "ip6tables"; argv[i++] = cmd ? "-A" : "-D"; argv[i++] = global_data->vrrp_iptables_inchain; argv[i++] = "-d"; argv[i++] = addr_str; if (IN6_IS_ADDR_LINKLOCAL(&ipaddress->u.sin6_addr)) { if_specifier = i; argv[i++] = "-i"; argv[i++] = ifname; } argv[i++] = "-p"; argv[i++] = "icmpv6"; argv[i++] = "--icmpv6-type"; type_specifier = i; argv[i++] = "136"; argv[i++] = "-j"; argv[i++] = "ACCEPT"; argv[i] = NULL; if (fork_exec(argv) < 0 && !force) log_message(LOG_ERR, "Failed to %s ip6table rule to accept NAs sent" " to vip %s", (cmd) ? "set" : "remove", addr_str); argv[type_specifier] = "135"; if (fork_exec(argv) < 0 && !force) log_message(LOG_ERR, "Failed to %s ip6table rule to accept NSs sent" " to vip %s", (cmd) ? "set" : "remove", addr_str); 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"; /* Allow NSs to be sent - this should only happen if the underlying interface doesn't have an IPv6 address */ if (fork_exec(argv) < 0 && !force) log_message(LOG_ERR, "Failed to %s ip6table rule to allow NSs to be" " sent from vip %s", (cmd) ? "set" : "remove", addr_str); argv[type_specifier] = "136"; /* Allow NAs to be sent in reply to an NS */ if (fork_exec(argv) < 0 && !force) log_message(LOG_ERR, "Failed to %s ip6table rule to allow NAs to be" " sent from vip %s", (cmd) ? "set" : "remove", addr_str); }
void format_iproute(ip_route_t *route, char *buf, size_t buf_len) { char *op = buf; char *buf_end = buf + buf_len; nexthop_t *nh; element e; if (route->type != RTN_UNICAST) op += snprintf(op, buf_end - op, " %s", get_rttables_rtntype(route->type)); if (route->dst) { op += snprintf(op, buf_end - op, " %s", ipaddresstos(NULL, route->dst)); if ((route->dst->ifa.ifa_family == AF_INET && route->dst->ifa.ifa_prefixlen != 32 ) || (route->dst->ifa.ifa_family == AF_INET6 && route->dst->ifa.ifa_prefixlen != 128 )) op += snprintf(op, buf_end - op, "/%u", route->dst->ifa.ifa_prefixlen); } else op += snprintf(op, buf_end - op, " %s", "default"); if (route->src) { op += snprintf(op, buf_end - op, " from %s", ipaddresstos(NULL, route->src)); if ((route->src->ifa.ifa_family == AF_INET && route->src->ifa.ifa_prefixlen != 32 ) || (route->src->ifa.ifa_family == AF_INET6 && route->src->ifa.ifa_prefixlen != 128 )) op += snprintf(op, buf_end - op, "/%u", route->src->ifa.ifa_prefixlen); } //#ifdef _HAVE_RTA_NEWDST_ // /* MPLS only */ // if (route->as_to) // op += snprintf(op, buf_end - op, " as to %s", ipaddresstos(NULL, route->as_to)); //#endif if (route->pref_src) op += snprintf(op, buf_end - op, " src %s", ipaddresstos(NULL, route->pref_src)); if (route->mask & IPROUTE_BIT_DSFIELD) op += snprintf(op, buf_end - op, " tos %u", route->tos); #ifdef _HAVE_RTA_ENCAP_ if (route->encap.type != LWTUNNEL_ENCAP_NONE) op += print_encap(op, buf_end - op, &route->encap); #endif if (route->via) op += snprintf(op, buf_end - op, " via %s %s", route->via->ifa.ifa_family == AF_INET6 ? "inet6" : "inet", ipaddresstos(NULL, route->via)); if (route->oif) op += snprintf(op, buf_end - op, " dev %s", route->oif->ifname); if (route->table != RT_TABLE_MAIN) op += snprintf(op, buf_end - op, " table %u", route->table); if (route->mask & IPROUTE_BIT_PROTOCOL) op += snprintf(op, buf_end - op, " proto %u", route->protocol); if (route->mask & IPROUTE_BIT_SCOPE) op += snprintf(op, buf_end - op, " scope %u", route->scope); if (route->mask & IPROUTE_BIT_METRIC) op += snprintf(op, buf_end - op, " metric %u", route->metric); if (route->family == AF_INET && route->flags & RTNH_F_ONLINK) op += snprintf(op, buf_end - op, " %s", "onlink"); if (route->realms) { if (route->realms & 0xFFFF0000) op += snprintf(op, buf_end - op, " realms %d/", route->realms >> 16); else op += snprintf(op, buf_end - op, " realm "); op += snprintf(op, buf_end - op, "%d", route->realms & 0xFFFF); }
void format_iprule(ip_rule_t *rule, char *buf, size_t buf_len) { char *op = buf; char *buf_end = buf + buf_len; if (!rule->to_addr && !rule->from_addr && rule->family == AF_INET6) op += snprintf(op, (size_t)(buf_end - op), "inet6 "); if (rule->invert) op += snprintf(op, (size_t)(buf_end - op), "not "); if (rule->from_addr) op += snprintf(op, (size_t)(buf_end - op), "from %s", ipaddresstos(NULL, rule->from_addr)); else op += snprintf(op, (size_t)(buf_end - op), "from all" ); if (rule->to_addr) op += snprintf(op, (size_t)(buf_end - op), " to %s", ipaddresstos(NULL, rule->to_addr)); if (rule->mask & IPRULE_BIT_PRIORITY) op += snprintf(op, (size_t)(buf_end - op), " priority %u", rule->priority); op += snprintf(op, (size_t)(buf_end - op), " tos 0x%x", rule->tos); if (rule->mask & (IPRULE_BIT_FWMARK | IPRULE_BIT_FWMASK)) { op += snprintf(op, (size_t)(buf_end - op), " fwmark 0x%x", rule->fwmark); if (rule->mask & IPRULE_BIT_FWMASK && rule->fwmask != 0xffffffff) op += snprintf(op, (size_t)(buf_end - op), "/0x%x", rule->fwmask); } if (rule->iif) #if HAVE_DECL_FRA_OIFNAME op += snprintf(op, (size_t)(buf_end - op), " iif %s", rule->iif->ifname); #else op += snprintf(op, (size_t)(buf_end - op), " dev %s", rule->iif->ifname); #endif #if HAVE_DECL_FRA_OIFNAME if (rule->oif) op += snprintf(op, (size_t)(buf_end - op), " oif %s", rule->oif->ifname); #endif #if HAVE_DECL_FRA_SUPPRESS_PREFIXLEN if (rule->suppress_prefix_len != -1) op += snprintf(op, (size_t)(buf_end - op), " suppress_prefixlen %u", rule->suppress_prefix_len); #endif #if HAVE_DECL_FRA_SUPPRESS_IFGROUP if (rule->mask & IPRULE_BIT_SUP_GROUP) op += snprintf(op, (size_t)(buf_end - op), " suppress_ifgroup %d", rule->suppress_group); #endif #if HAVE_DECL_FRA_TUN_ID if (rule->tunnel_id) op += snprintf(op, (size_t)(buf_end - op), " tunnel-id %" PRIu64, rule->tunnel_id); #endif #if HAVE_DECL_FRA_UID_RANGE if (rule->mask & IPRULE_BIT_UID_RANGE) op += snprintf(op, (size_t)(buf_end - op), " uidrange %" PRIu32 "-%" PRIu32, rule->uid_range.start, rule->uid_range.end); #endif #if HAVE_DECL_FRA_L3MDEV if (rule->l3mdev) op += snprintf(op, (size_t)(buf_end - op), " l3mdev"); #endif #if HAVE_DECL_FRA_PROTOCOL if (rule->mask & IPRULE_BIT_PROTOCOL) op += snprintf(op, (size_t)(buf_end - op), " protocol %u", rule->protocol); #endif #if HAVE_DECL_FRA_IP_PROTO if (rule->mask & IPRULE_BIT_IP_PROTO) op += snprintf(op, (size_t)(buf_end - op), " ipproto %u", rule->ip_proto); #endif #if HAVE_DECL_FRA_SPORT_RANGE if (rule->mask & IPRULE_BIT_SPORT_RANGE) op += snprintf(op, (size_t)(buf_end - op), " sport %hu-%hu", rule->src_port.start, rule->src_port.end); #endif #if HAVE_DECL_FRA_DPORT_RANGE if (rule->mask & IPRULE_BIT_DPORT_RANGE) op += snprintf(op, (size_t)(buf_end - op), " dport %hu-%hu", rule->dst_port.start, rule->dst_port.end); #endif if (rule->realms) op += snprintf(op, (size_t)(buf_end - op), " realms %d/%d", rule->realms >> 16, rule->realms & 0xffff); if (rule->action == FR_ACT_TO_TBL) op += snprintf(op, (size_t)(buf_end - op), " lookup %u", rule->table); else if (rule->action == FR_ACT_GOTO) op += snprintf(op, (size_t)(buf_end - op), " goto %u", rule->goto_target); else if (rule->action == FR_ACT_NOP) op += snprintf(op, (size_t)(buf_end - op), " nop"); else op += snprintf(op, (size_t)(buf_end - op), " type %s", get_rttables_rtntype(rule->action)); if (rule->dont_track) op += snprintf(op, (size_t)(buf_end - op), " no_track"); if (rule->track_group) op += snprintf(op, (size_t)(buf_end - op), " track_group %s", rule->track_group->gname); }