static void open_api(void) { s32 old_umask; u32 i; struct sockaddr_un u; struct stat st; api_fd = socket(PF_UNIX, SOCK_STREAM, 0); if (api_fd < 0) printf("\n FATAL: socket(PF_UNIX) failed."); memset(&u, 0, sizeof(u)); u.sun_family = AF_UNIX; if (strlen((char*)api_sock) >= sizeof(u.sun_path)) printf("\n FATAL: API socket filename is too long for sockaddr_un (blame Unix)."); strcpy(u.sun_path, (char*)api_sock); /* This is bad, but you can't do any better with standard unix socket semantics today :-( */ if (!stat((char*)api_sock, &st) && !S_ISSOCK(st.st_mode)) printf("\n FATAL: '%s' exists but is not a socket.", api_sock); if (unlink((char*)api_sock) && errno != ENOENT) printf("\n FATAL: unlink('%s') failed.", api_sock); old_umask = umask(0777 ^ API_MODE); if (bind(api_fd, (struct sockaddr*)&u, sizeof(u))) printf("\n FATAL: bind() on '%s' failed.", api_sock); umask(old_umask); if (listen(api_fd, api_max_conn)) printf("\n FATAL: listen() on '%s' failed.", api_sock); if (fcntl(api_fd, F_SETFL, O_NONBLOCK)) printf("\n FATAL: fcntl() to set O_NONBLOCK on API listen socket fails."); api_cl = DFL_ck_alloc(api_max_conn * sizeof(struct api_client)); for (i = 0; i < api_max_conn; i++) api_cl[i].fd = -1; SAYF("[+] Listening on API socket '%s' (max %u clients).\n", api_sock, api_max_conn); }
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. */ }