/* Process TCP packets * Return 0 to accept packet, otherwise to drop packet */ int process_tcp_packet(struct mypacket *packet, char inout) { int ret = 0; struct myiphdr *iphdr = packet->iphdr; struct mytcphdr *tcphdr = packet->tcphdr; unsigned char *payload = packet->payload; char sip[16], dip[16]; ip2str(iphdr->saddr, sip); ip2str(iphdr->daddr, dip); unsigned short sport, dport; //unsigned int seq, ack; sport = ntohs(tcphdr->th_sport); dport = ntohs(tcphdr->th_dport); //seq = tcphdr->th_seq; //ack = tcphdr->th_ack; log_debug("[TCP] This packet goes from %s:%d to %s:%d", sip, sport, dip, dport); log_debug("TCP flags: %s", tcp_flags(tcphdr->th_flags)); struct fourtuple fourtp; fourtp.saddr = iphdr->saddr; fourtp.daddr = iphdr->daddr; fourtp.sport = tcphdr->th_sport; fourtp.dport = tcphdr->th_dport; // for testing uni-directional packet forwarding to bypass IP blocking //if (dport == 80 && is_blocked_ip(dip)) { // log_debug("Going to forward that packet!!!"); // unsigned int newlen = packet->len + 4; // char *newpkt = (char*)malloc(newlen); // memcpy(newpkt, packet->data, packet->len); // *(u_int32_t*)(newpkt + packet->len) = iphdr->daddr; // ip_hdr(newpkt)->daddr = str2ip(PACKET_FORWARDER); // send_raw(newpkt, newlen); // log_debug("sent!!!"); // return 0; //} if (tcphdr->th_flags == TCP_SYN) { // Processing outgoing SYN packet. // Uploading diagnostic log is disabled. (2017.9.1) //if (strcmp(dip, FEEDBACK_SERVER_IP) == 0) // return 0; // choose a strategy for the newly created connection int sid = choose_strategy_by_historical_result(iphdr->daddr); log_debug("Using strategy %s", g_strats[sid].name); set_sid(&fourtp, sid); //cache_strategy(&fourtp, sid); if (g_strats[sid].process_syn) { ret = g_strats[sid].process_syn(packet); #ifndef EVALUATION if (ret) { need_evaluation(&fourtp); } #endif } } if (tcphdr->th_flags == (TCP_SYN | TCP_ACK)) { // Got a SYN-ACK from server // send an ACK with 1 TTL to make home router happy if (opt_inject_ack_with_one_ttl) send_ACK_with_one_ttl(dip, dport, sip, sport, tcphdr->th_ack, htonl(ntohl(tcphdr->th_seq)+1)); struct fourtuple reverse_fourtp; reverse_fourtp.saddr = iphdr->daddr; reverse_fourtp.daddr = iphdr->saddr; reverse_fourtp.sport = tcphdr->th_dport; reverse_fourtp.dport = tcphdr->th_sport; int sid = get_sid(&reverse_fourtp); if (sid >= 0) { if (get_ttl(iphdr->saddr) == 0) { // if TTL hasn't been initialized // find initial TTL from SYN/ACK packet int ttl = choose_appropriate_ttl(iphdr->ttl); set_ttl(iphdr->saddr, ttl); } if (g_strats[sid].process_synack) { ret = g_strats[sid].process_synack(packet); #ifndef EVALUATION if (ret) { need_evaluation(&reverse_fourtp); } #endif } } else if (sid == -1) { ret = process_synack_for_ttl_probing(packet); } //if (opt_inject_syn_and_syn_ack_with_one_ttl) // send_one_ttl_SYN_and_SYN_ACK(dip, dport, sip, sport, tcphdr->th_ack, tcphdr->th_seq); } else if ((tcphdr->th_flags & TCP_ACK) && !(tcphdr->th_flags & (TCP_SYN | TCP_RST))) { // ignore ACK packets without payload if (packet->payload_len == 0) return 0; if (dport == 80) { if ((payload[0] == 'G' && payload[1] == 'E' && payload[2] == 'T' && payload[3] == ' ') || (payload[0] == 'P' && payload[1] == 'O' && payload[2] == 'S' && payload[3] == 'T' && payload[4] == ' ')) { // Got a outgoing HTTP request log_debug("[TCP] Sent a HTTP request from %s:%d to %s:%d.", sip, sport, dip, dport); int i, j, k, l; //char req_line[1000]; //for (i = 0; i < 1000; i++) { // if (payload[i] == '\r' || payload[i] == '\n') { // req_line[i] = 0; // break; // } // req_line[i] = payload[i]; //} // Generate the HTTP request line. Format: GET/POST domain/url. e.g. GET www.google.com/index.php char req_line2[1000]; // copy GET/POST for (i = 0; payload[i] != ' ' && i < packet->payload_len; i++) { req_line2[i] = payload[i]; } req_line2[i++] = ' '; k = i; // find Host field for (j = i; j < packet->payload_len; j++) { if (payload[j] == 'H' && payload[j+1] == 'o' && payload[j+2] == 's' && payload[j+3] == 't' && payload[j+4] == ':' && (payload[j-1] == '\r' || payload[j-1] == '\n')) { j += 5; // copy Host value while (payload[j] == ' ') j++; for (l = 0; l < 99 && j+l < packet->payload_len; l++) { if (payload[j+l] == '\r' || payload[j+l] == '\n') break; req_line2[k++] = payload[j+l]; } break; } } // copy the rest of request line for (; i < 900 && i < packet->payload_len; i++) { if (payload[i] == '\r' || payload[i] == '\n') { break; } req_line2[k++] = payload[i]; } req_line2[k] = 0; log_debug("[TCP] %s", req_line2); int sid = get_sid(&fourtp); if (sid >= 0 && g_strats[sid].process_request) { ret = g_strats[sid].process_request(packet); #ifndef EVALUATION if (ret) { need_evaluation(&fourtp); } #endif } #ifdef EVALUATION if (strstr(req_line2, "ultrasurf") || strstr(req_line2, "goodword")) { need_evaluation(&fourtp); } #endif cache_http_request(&fourtp, req_line2); } } else if (sport == 80) { if (payload[0] == 'H' && payload[1] == 'T' && payload[2] == 'T' && payload[3] == 'P') { // Got a incoming HTTP response log_debug("[TCP] Got a HTTP response from %s:%d to %s:%d.", sip, sport, dip, dport); process_http_response(&fourtp, tcphdr->th_seq, iphdr->ttl); } } else if (dport == 53) { // Got a DNS request over TCP log_debug("[TCP] Sent a DNS request from %s:%d to %s:%d.", sip, sport, dip, dport); int sid = get_sid(&fourtp); if (sid >= 0 && g_strats[sid].process_request) { ret = g_strats[sid].process_request(packet); #ifndef EVALUATION if (ret) { need_evaluation(&fourtp); } #endif } cache_dns_tcp_request(&fourtp); } else if (sport == 53) { // Got a DNS response over TCP, maybe triggered by our app, or maybe not log_debug("[TCP] Got a DNS response from %s:%d to %s:%d.", sip, sport, dip, dport); // parse the DNS response to get the first qname const unsigned char *dns_payload = packet->payload + 2; struct mydnshdr *dnshdr = (struct mydnshdr*)dns_payload; unsigned short txn_id = htons(dnshdr->txn_id); int qdcount = ntohs(dnshdr->questions); char qname[MAX_QNAME_LEN]; if (qdcount > 0) { //log_debug("Questions: %d", qdcount); unsigned char *ptr = (unsigned char *)(dnshdr + 1); { struct mydnsquery query; int j = 0, l; while (1) { for (l = *ptr++; l != 0; l--) { query.qname[j++] = *ptr++; if (j >= MAX_QNAME_LEN) { while (*ptr != 0) ptr++; break; } } if (*ptr == 0) { query.qname[j] = 0; ptr++; break; } query.qname[j++] = '.'; } query.qtype = (ptr[0] << 8) + ptr[1]; query.qclass = (ptr[2] << 8) + ptr[3]; log_debug("DNS Query: %s %d %d", query.qname, query.qtype, query.qclass); // use the first query to calc hash qname[0] = 0; strncat(qname, query.qname, MAX_QNAME_LEN - 1); } // Tell the caching thread to process the dns udp response // use DNS transaction ID and first query name as unique ID // transaction ID alone may cause collision process_dns_tcp_response(txn_id, qname, &fourtp, tcphdr->th_seq, iphdr->ttl, packet->payload, packet->payload_len); } } else if (dport == opt_vpn_port) { // outgoing packet int sid = get_sid(&fourtp); if (sid >= 0 && g_strats[sid].process_request) { ret = g_strats[sid].process_request(packet); if (ret) { if (opt_inject_syn_and_syn_ack_with_one_ttl == 1) send_one_ttl_SYN(sip, sport, dip, dport, tcphdr->th_seq); else if (opt_inject_syn_and_syn_ack_with_one_ttl == 2) send_one_ttl_SYN_and_SYN_ACK(sip, sport, dip, dport, tcphdr->th_seq, tcphdr->th_ack); } } } else if (sport == opt_vpn_port) { // incomine packet } else if (dport == opt_tor_port) { // outgoing packet int sid = get_sid(&fourtp); if (sid >= 0 && g_strats[sid].process_request) { ret = g_strats[sid].process_request(packet); if (ret) { if (opt_inject_syn_and_syn_ack_with_one_ttl == 1) send_one_ttl_SYN(sip, sport, dip, dport, tcphdr->th_seq); else if (opt_inject_syn_and_syn_ack_with_one_ttl == 2) send_one_ttl_SYN_and_SYN_ACK(sip, sport, dip, dport, tcphdr->th_seq, tcphdr->th_ack); } } } else if (sport == opt_tor_port) { // incomine packet } else { // TODO: for all other protocols. This branch is a piece of temporary code, should be re-write. if (inout == 0) { // incoming packet log_debug("this is an incoming packet."); } else { // outgoing packet log_debug("this is an outgoing packet."); int sid = get_sid(&fourtp); if (sid >= 0 && g_strats[sid].process_request) { ret = g_strats[sid].process_request(packet); if (ret) { if (opt_inject_syn_and_syn_ack_with_one_ttl == 1) send_one_ttl_SYN(sip, sport, dip, dport, tcphdr->th_seq); else if (opt_inject_syn_and_syn_ack_with_one_ttl == 2) send_one_ttl_SYN_and_SYN_ACK(sip, sport, dip, dport, tcphdr->th_seq, tcphdr->th_ack); } } } } } else if (tcphdr->th_flags & TCP_RST) { // Got an incoming RST log_debug("[TCP] Got an incoming RST from %s:%d to %s:%d.", sip, sport, dip, dport); process_incoming_RST(packet); } return ret; }
static void probe_print(scamper_probe_t *probe) { size_t iphl; char tcp[16]; char pos[32]; char addr[128]; char icmp[16]; char tos[8]; assert(probe->pr_ip_dst != NULL); scamper_addr_tostr(probe->pr_ip_dst, addr, sizeof(addr)); tos[0] = '\0'; icmp[0] = '\0'; if(probe->pr_ip_proto == IPPROTO_TCP) { if((probe->pr_ip_tos & IPTOS_ECN_CE) == IPTOS_ECN_CE) snprintf(tos, sizeof(tos), ", ce"); else if(probe->pr_ip_tos & IPTOS_ECN_ECT1) snprintf(tos, sizeof(tos), ", ect1"); else if(probe->pr_ip_tos & IPTOS_ECN_ECT0) snprintf(tos, sizeof(tos), ", ect0"); } if(probe->pr_ip_dst->type == SCAMPER_ADDR_TYPE_IPV4) { if(scamper_ip4_hlen(probe, &iphl) != 0) return; if((probe->pr_ip_off & IP_OFFMASK) != 0) { scamper_debug("tx", "frag %s %04x:%d ttl %d, len %d", addr, probe->pr_ip_id, probe->pr_ip_off << 3, probe->pr_ip_ttl, iphl + probe->pr_len); return; } switch(probe->pr_ip_proto) { case IPPROTO_UDP: scamper_debug("tx", "udp %s, ttl %d, %d:%d, len %d", addr, probe->pr_ip_ttl, probe->pr_udp_sport, probe->pr_udp_dport, iphl + 8 + probe->pr_len); break; case IPPROTO_TCP: scamper_debug("tx", "tcp %s%s, ttl %d, %d:%d%s, ipid %04x, %s, len %d", addr, tos, probe->pr_ip_ttl, probe->pr_tcp_sport, probe->pr_tcp_dport, tcp_flags(tcp, sizeof(tcp), probe), probe->pr_ip_id, tcp_pos(pos, sizeof(pos), probe), iphl + scamper_tcp4_hlen(probe) + probe->pr_len); break; case IPPROTO_ICMP: if(probe->pr_icmp_type == ICMP_ECHO) { if(probe->pr_icmp_sum != 0) { snprintf(icmp, sizeof(icmp), ", sum %04x", ntohs(probe->pr_icmp_sum)); } scamper_debug("tx", "icmp %s echo, ttl %d%s, seq %d, len %d", addr, probe->pr_ip_ttl, icmp, probe->pr_icmp_seq, iphl + 8 + probe->pr_len); } else if(probe->pr_icmp_type == ICMP_UNREACH) { if(probe->pr_icmp_code == ICMP_UNREACH_NEEDFRAG) snprintf(icmp,sizeof(icmp),"ptb %d", probe->pr_icmp_mtu); else snprintf(icmp,sizeof(icmp),"unreach %d", probe->pr_icmp_code); scamper_debug("tx", "icmp %s %s, len %d", addr, icmp, iphl + 8 + probe->pr_len); } else { scamper_debug("tx", "icmp %s type %d, code %d, len %d", addr, probe->pr_icmp_type, probe->pr_icmp_code, iphl + 8 + probe->pr_len); } break; } } else if(probe->pr_ip_dst->type == SCAMPER_ADDR_TYPE_IPV6) { if(scamper_ip6_hlen(probe, &iphl) != 0) return; if(probe->pr_ip_off != 0) { scamper_debug("tx", "frag %s off %04x, ttl %d, len %d", addr, probe->pr_ip_off, probe->pr_ip_ttl, iphl + probe->pr_len); return; } switch(probe->pr_ip_proto) { case IPPROTO_UDP: scamper_debug("tx", "udp %s, ttl %d, %d:%d, len %d", addr, probe->pr_ip_ttl, probe->pr_udp_sport, probe->pr_udp_dport, iphl + 8 + probe->pr_len); break; case IPPROTO_TCP: scamper_debug("tx", "tcp %s%s, ttl %d, %d:%d%s, %s, len %d", addr, tos, probe->pr_ip_ttl, probe->pr_tcp_sport, probe->pr_tcp_dport, tcp_flags(tcp, sizeof(tcp), probe), tcp_pos(pos, sizeof(pos), probe), iphl + scamper_tcp6_hlen(probe) + probe->pr_len); break; case IPPROTO_ICMPV6: if(probe->pr_icmp_type == ICMP6_ECHO_REQUEST) { if(probe->pr_icmp_sum != 0) { snprintf(icmp, sizeof(icmp), ", sum %04x", ntohs(probe->pr_icmp_sum)); } scamper_debug("tx", "icmp %s echo, ttl %d%s, seq %d, len %d", addr, probe->pr_ip_ttl, icmp, probe->pr_icmp_seq, iphl + 8 + probe->pr_len); } else if(probe->pr_icmp_type == ICMP6_PACKET_TOO_BIG) { scamper_debug("tx", "icmp %s ptb %d, len %d", addr, probe->pr_icmp_mtu, iphl + 8 + probe->pr_len); } else if(probe->pr_icmp_type == ICMP6_DST_UNREACH) { scamper_debug("tx", "icmp %s unreach %d, len %d", addr, probe->pr_icmp_code, iphl + 8 + probe->pr_len); } else { scamper_debug("tx", "icmp %s type %d, code %d, len %d", addr, probe->pr_icmp_type, probe->pr_icmp_code, iphl + 8 + probe->pr_len); } break; } } return; }