#define BUILD_MATCH #define MODULE_DATATYPE struct ipt_addrtype_info #define MODULE_NAME "addrtype" #define __USE_GNU #include "../module_iface.h" #include #include #include #include static char *rtn_names[] = { "UNSPEC", "UNICAST", "LOCAL", "BROADCAST", "ANYCAST", "MULTICAST", "BLACKHOLE", "UNREACHABLE", "PROHIBIT", "THROW", "NAT", "XRESOLVE", NULL }; static void setup(void *myinfo, unsigned int *nfcache) { *nfcache |= NFC_UNKNOWN; } static int parse_value(SV *value, u_int16_t *mask, int *invert) { SV *sv = NULL; AV *av = NULL; SV **svp; int index = 0, i, len; char *str; if (SvROK(value) && (av = (AV *)SvRV(value)) && (SvTYPE((SV *)av) == SVt_PVAV)) { if (index <= av_len(av)) { svp = av_fetch(av, index, 0); sv = *svp; } } else if (SvPOK(value)) sv = value; else { SET_ERRSTR("Argument must be string or array"); return(FALSE); } while (sv) { if (!SvPOK(sv)) { SET_ERRSTR("Array element must be string"); return(FALSE); } str = SvPV(sv, len); if (av && !strncasecmp(str, "INVERT", len)) *invert = 1; else { for (i = 0; i < sizeof(rtn_names) / sizeof(char *); i++) { printf("str is \"%s\", rtn_names[%d] is \"%s\"\n", str, i, rtn_names[i]); if (!strncasecmp(str, rtn_names[i], len)) { *mask |= (1 << i); break; } } if (i >= sizeof(rtn_names) / sizeof(char *)) { SET_ERRSTR("Couldn't parse type name"); return(FALSE); } } if (av && index <= av_len(av)) { svp = av_fetch(av, index, 0); sv = *svp; index++; } else sv = NULL; } return(TRUE); } #define IPT_ADDRTYPE_OPT_SRCTYPE 0x1 #define IPT_ADDRTYPE_OPT_DSTTYPE 0x2 static int parse_field(char *field, SV *value, void *myinfo, unsigned int *nfcache, struct ipt_entry *entry, int *flags) { MODULE_DATATYPE *info = (void *)(*(MODULE_ENTRYTYPE **)myinfo)->data; char *temp; if (!strcmp(field, "src-type")) { if (!parse_value(value, &info->source, &info->invert_source)) { temp = strdup(SvPV_nolen(ERROR_SV)); SET_ERRSTR("%s: %s", field, temp); free(temp); return(FALSE); } *flags |= IPT_ADDRTYPE_OPT_SRCTYPE; return(TRUE); } else if (!strcmp(field, "dst-type")) { if (!parse_value(value, &info->dest, &info->invert_dest)) { temp = strdup(SvPV_nolen(ERROR_SV)); SET_ERRSTR("%s: %s", field, temp); free(temp); return(FALSE); } *flags |= IPT_ADDRTYPE_OPT_DSTTYPE; return(TRUE); } return(FALSE); } static SV *flag_list(u_int16_t mask, int invert) { AV *flags = newAV(); int i; for (i = 0; i < sizeof(rtn_names) / sizeof(char *); i++) { if (mask & (1 << i)) av_push((AV *)flags, newSVpv(rtn_names[i], strlen(rtn_names[i]))); } if (invert) av_push((AV *)flags, newSVpv("INVERT", 6)); return(newRV((SV *)flags)); } static void get_fields(HV *ent_hash, void *myinfo, struct ipt_entry *entry) { MODULE_DATATYPE *info = (void *)((MODULE_ENTRYTYPE *)myinfo)->data; if (info->source) hv_store(ent_hash, "src-type", 8, flag_list(info->source, info->invert_source), 0); if (info->dest) hv_store(ent_hash, "dst-type", 8, flag_list(info->dest, info->invert_dest), 0); } int final_check(void *myinfo, int flags) { if(!flags) { SET_ERRSTR("addrtype requires at least one of 'src-type', 'dst-type'"); return(FALSE); } return(TRUE); } static ModuleDef _module = { .type = MODULE_TYPE, .name = MODULE_NAME, .size = IPT_ALIGN(sizeof(MODULE_DATATYPE)), .size_uspace = IPT_ALIGN(sizeof(MODULE_DATATYPE)), .setup = setup, .parse_field = parse_field, .get_fields = get_fields, .final_check = final_check, }; ModuleDef *init(void) { return(&_module); } /* vim: ts=4 */