static void config_parse_sys(u8* val) { if (cur_sys) { cur_sys = NULL; cur_sys_cnt = 0; } while (*val) { u8* nxt; u8 is_cl = 0, orig; u32 i; while (isblank(*val) || *val == ',') val++; if (*val == '@') { is_cl = 1; val++; } nxt = val; while (isalnum(*nxt) || (*nxt && strchr(NAME_CHARS, *nxt))) nxt++; if (nxt == val || (*nxt && *nxt != ',')) FATAL("Malformed sys entry in line %u.", line_no); orig = *nxt; *nxt = 0; if (is_cl) { for (i = 0; i < class_cnt; i++) if (!strcasecmp((char*)val, (char*)fp_os_classes[i])) break; if (i == class_cnt) FATAL("Unknown class '%s' in line %u.", val, line_no); i |= SYS_CLASS_FLAG; } else { for (i = 0; i < name_cnt; i++) if (!strcasecmp((char*)val, (char*)fp_os_names[i])) break; if (i == name_cnt) { fp_os_names = DFL_ck_realloc(fp_os_names, (name_cnt + 1) * sizeof(u8*)); fp_os_names[name_cnt++] = DFL_ck_memdup_str(val, nxt - val); } } cur_sys = DFL_ck_realloc(cur_sys, (cur_sys_cnt + 1) * 4); cur_sys[cur_sys_cnt++] = i; *nxt = orig; val = nxt; } }
u32 lookup_name_id(u8* name, u8 len) { u32 i; for (i = 0; i < name_cnt; i++) if (!strncasecmp((char*)name, (char*)fp_os_names[i], len) && !fp_os_names[i][len]) break; if (i == name_cnt) { sig_name = name_cnt; fp_os_names = DFL_ck_realloc(fp_os_names, (name_cnt + 1) * sizeof(u8*)); fp_os_names[name_cnt++] = DFL_ck_memdup_str(name, len); } return i; }
static void config_parse_classes(u8* val) { while (*val) { u8* nxt; while (isblank(*val) || *val == ',') val++; nxt = val; while (isalnum(*nxt)) nxt++; if (nxt == val || (*nxt && *nxt != ',')) FATAL("Malformed class entry in line %u.", line_no); fp_os_classes = DFL_ck_realloc(fp_os_classes, (class_cnt + 1) * sizeof(u8*)); fp_os_classes[class_cnt++] = DFL_ck_memdup_str(val, nxt - val); val = nxt; } }
void tcp_register_sig(u8 to_srv, u8 generic, s32 sig_class, u32 sig_name, u8* sig_flavor, u32 label_id, u32* sys, u32 sys_cnt, u8* val, u32 line_no) { s8 ver, win_type, pay_class; u8 opt_layout[MAX_TCP_OPT]; u8 opt_cnt = 0, bad_ttl = 0; s32 ittl, olen, mss, win, scale, opt_eol_pad = 0; u32 quirks = 0, bucket, opt_hash; u8* nxt; struct tcp_sig* tsig; struct tcp_sig_record* trec; /* IP version */ switch (*val) { case '4': ver = IP_VER4; break; case '6': ver = IP_VER6; break; case '*': ver = -1; break; default: FATAL("Unrecognized IP version in line %u.", line_no); } if (val[1] != ':') FATAL("Malformed signature in line %u.", line_no); val += 2; /* Initial TTL (possibly ttl+dist or ttl-) */ nxt = val; while (isdigit(*nxt)) nxt++; if (*nxt != ':' && *nxt != '+' && *nxt != '-') FATAL("Malformed signature in line %u.", line_no); ittl = atol((char*)val); if (ittl < 1 || ittl > 255) FATAL("Bogus initial TTL in line %u.", line_no); val = nxt + 1; if (*nxt == '-' && nxt[1] == ':') { bad_ttl = 1; val += 2; } else if (*nxt == '+') { s32 ittl_add; nxt++; while (isdigit(*nxt)) nxt++; if (*nxt != ':') FATAL("Malformed signature in line %u.", line_no); ittl_add = atol((char*)val); if (ittl_add < 0 || ittl + ittl_add > 255) FATAL("Bogus initial TTL in line %u.", line_no); ittl += ittl_add; val = nxt + 1; } /* Length of IP options */ nxt = val; while (isdigit(*nxt)) nxt++; if (*nxt != ':') FATAL("Malformed signature in line %u.", line_no); olen = atol((char*)val); if (olen < 0 || olen > 255) FATAL("Bogus IP option length in line %u.", line_no); val = nxt + 1; /* MSS */ if (*val == '*' && val[1] == ':') { mss = -1; val += 2; } else { nxt = val; while (isdigit(*nxt)) nxt++; if (*nxt != ':') FATAL("Malformed signature in line %u.", line_no); mss = atol((char*)val); if (mss < 0 || mss > 65535) FATAL("Bogus MSS in line %u.", line_no); val = nxt + 1; } /* window size, followed by comma */ if (*val == '*' && val[1] == ',') { win_type = WIN_TYPE_ANY; win = 0; val += 2; } else if (*val == '%') { win_type = WIN_TYPE_MOD; val++; nxt = val; while (isdigit(*nxt)) nxt++; if (*nxt != ',') FATAL("Malformed signature in line %u.", line_no); win = atol((char*)val); if (win < 2 || win > 65535) FATAL("Bogus '%%' value in line %u.", line_no); val = nxt + 1; } else if (!strncmp((char*)val, "mss*", 4) || !strncmp((char*)val, "mtu*", 4)) { win_type = (val[1] == 's') ? WIN_TYPE_MSS : WIN_TYPE_MTU; val += 4; nxt = val; while (isdigit(*nxt)) nxt++; if (*nxt != ',') FATAL("Malformed signature in line %u.", line_no); win = atol((char*)val); if (win < 1 || win > 1000) FATAL("Bogus MSS/MTU multiplier in line %u.", line_no); val = nxt + 1; } else { win_type = WIN_TYPE_NORMAL; nxt = val; while (isdigit(*nxt)) nxt++; if (*nxt != ',') FATAL("Malformed signature in line %u.", line_no); win = atol((char*)val); if (win < 0 || win > 65535) FATAL("Bogus window size in line %u.", line_no); val = nxt + 1; } /* Window scale */ if (*val == '*' && val[1] == ':') { scale = -1; val += 2; } else { nxt = val; while (isdigit(*nxt)) nxt++; if (*nxt != ':') FATAL("Malformed signature in line %u.", line_no); scale = atol((char*)val); if (scale < 0 || scale > 255) FATAL("Bogus window scale in line %u.", line_no); val = nxt + 1; } /* Option layout */ memset(opt_layout, 0, sizeof(opt_layout)); while (*val != ':') { if (opt_cnt >= MAX_TCP_OPT) FATAL("Too many TCP options in line %u.", line_no); if (!strncmp((char*)val, "eol", 3)) { opt_layout[opt_cnt++] = TCPOPT_EOL; val += 3; if (*val != '+') FATAL("Malformed EOL option in line %u.", line_no); val++; nxt = val; while (isdigit(*nxt)) nxt++; if (!*nxt) FATAL("Truncated options in line %u.", line_no); if (*nxt != ':') FATAL("EOL must be the last option in line %u.", line_no); opt_eol_pad = atol((char*)val); if (opt_eol_pad < 0 || opt_eol_pad > 255) FATAL("Bogus EOL padding in line %u.", line_no); val = nxt; } else if (!strncmp((char*)val, "nop", 3)) { opt_layout[opt_cnt++] = TCPOPT_NOP; val += 3; } else if (!strncmp((char*)val, "mss", 3)) { opt_layout[opt_cnt++] = TCPOPT_MAXSEG; val += 3; } else if (!strncmp((char*)val, "ws", 2)) { opt_layout[opt_cnt++] = TCPOPT_WSCALE; val += 2; } else if (!strncmp((char*)val, "sok", 3)) { opt_layout[opt_cnt++] = TCPOPT_SACKOK; val += 3; } else if (!strncmp((char*)val, "sack", 4)) { opt_layout[opt_cnt++] = TCPOPT_SACK; val += 4; } else if (!strncmp((char*)val, "ts", 2)) { opt_layout[opt_cnt++] = TCPOPT_TSTAMP; val += 2; } else if (*val == '?') { s32 optno; val++; nxt = val; while (isdigit(*nxt)) nxt++; if (*nxt != ':' && *nxt != ',') FATAL("Malformed '?' option in line %u.", line_no); optno = atol((char*)val); if (optno < 0 || optno > 255) FATAL("Bogus '?' option in line %u.", line_no); opt_layout[opt_cnt++] = optno; val = nxt; } else { FATAL("Unrecognized TCP option in line %u.", line_no); } if (*val == ':') break; if (*val != ',') FATAL("Malformed TCP options in line %u.", line_no); val++; } val++; opt_hash = hash32(opt_layout, opt_cnt, hash_seed); /* Quirks */ while (*val != ':') { if (!strncmp((char*)val, "df", 2)) { if (ver == IP_VER6) FATAL("'df' is not valid for IPv6 in line %d.", line_no); quirks |= QUIRK_DF; val += 2; } else if (!strncmp((char*)val, "id+", 3)) { if (ver == IP_VER6) FATAL("'id+' is not valid for IPv6 in line %d.", line_no); quirks |= QUIRK_NZ_ID; val += 3; } else if (!strncmp((char*)val, "id-", 3)) { if (ver == IP_VER6) FATAL("'id-' is not valid for IPv6 in line %d.", line_no); quirks |= QUIRK_ZERO_ID; val += 3; } else if (!strncmp((char*)val, "ecn", 3)) { quirks |= QUIRK_ECN; val += 3; } else if (!strncmp((char*)val, "0+", 2)) { if (ver == IP_VER6) FATAL("'0+' is not valid for IPv6 in line %d.", line_no); quirks |= QUIRK_NZ_MBZ; val += 2; } else if (!strncmp((char*)val, "flow", 4)) { if (ver == IP_VER4) FATAL("'flow' is not valid for IPv4 in line %d.", line_no); quirks |= QUIRK_FLOW; val += 4; } else if (!strncmp((char*)val, "seq-", 4)) { quirks |= QUIRK_ZERO_SEQ; val += 4; } else if (!strncmp((char*)val, "ack+", 4)) { quirks |= QUIRK_NZ_ACK; val += 4; } else if (!strncmp((char*)val, "ack-", 4)) { quirks |= QUIRK_ZERO_ACK; val += 4; } else if (!strncmp((char*)val, "uptr+", 5)) { quirks |= QUIRK_NZ_URG; val += 5; } else if (!strncmp((char*)val, "urgf+", 5)) { quirks |= QUIRK_URG; val += 5; } else if (!strncmp((char*)val, "pushf+", 6)) { quirks |= QUIRK_PUSH; val += 6; } else if (!strncmp((char*)val, "ts1-", 4)) { quirks |= QUIRK_OPT_ZERO_TS1; val += 4; } else if (!strncmp((char*)val, "ts2+", 4)) { quirks |= QUIRK_OPT_NZ_TS2; val += 4; } else if (!strncmp((char*)val, "opt+", 4)) { quirks |= QUIRK_OPT_EOL_NZ; val += 4; } else if (!strncmp((char*)val, "exws", 4)) { quirks |= QUIRK_OPT_EXWS; val += 4; } else if (!strncmp((char*)val, "bad", 3)) { quirks |= QUIRK_OPT_BAD; val += 3; } else { FATAL("Unrecognized quirk in line %u.", line_no); } if (*val == ':') break; if (*val != ',') FATAL("Malformed quirks in line %u.", line_no); val++; } val++; /* Payload class */ if (!strcmp((char*)val, "*")) pay_class = -1; else if (!strcmp((char*)val, "0")) pay_class = 0; else if (!strcmp((char*)val, "+")) pay_class = 1; else FATAL("Malformed payload class in line %u.", line_no); /* Phew, okay, we're done. Now, create tcp_sig... */ tsig = DFL_ck_alloc(sizeof(struct tcp_sig)); tsig->opt_hash = opt_hash; tsig->opt_eol_pad = opt_eol_pad; tsig->quirks = quirks; tsig->ip_opt_len = olen; tsig->ip_ver = ver; tsig->ttl = ittl; tsig->mss = mss; tsig->win = win; tsig->win_type = win_type; tsig->wscale = scale; tsig->pay_class = pay_class; /* No need to set ts1, recv_ms, match, fuzzy, dist */ tcp_find_match(to_srv, tsig, 1, 0); if (tsig->matched) FATAL("Signature in line %u is already covered by line %u.", line_no, tsig->matched->line_no); /* Everything checks out, so let's register it. */ bucket = opt_hash % SIG_BUCKETS; sigs[to_srv][bucket] = DFL_ck_realloc(sigs[to_srv][bucket], (sig_cnt[to_srv][bucket] + 1) * sizeof(struct tcp_sig_record)); trec = sigs[to_srv][bucket] + sig_cnt[to_srv][bucket]; sig_cnt[to_srv][bucket]++; trec->generic = generic; trec->class_id = sig_class; trec->name_id = sig_name; trec->flavor = sig_flavor; trec->label_id = label_id; trec->sys = sys; trec->sys_cnt = sys_cnt; trec->line_no = line_no; trec->sig = tsig; trec->bad_ttl = bad_ttl; /* All done, phew. */ }