void init_package_head(ap_package_t *pkt, U8 data_type,U8 src_addr, U8 dst_addr, U8 port, U8 ttl, U8 type) { memset(pkt, 0, sizeof(ap_package_t)); set_src_addr(pkt, src_addr); set_dst_addr(pkt, dst_addr); set_port(pkt, port); set_ttl(pkt, ttl);//赋值为7 set_type(pkt, type);//type传入参数为0 set_CoS(pkt,data_type); }
void write_tcp( tcp_t *tcp, int len ) { if(len < sizeof(tcp_t)) { D(bug("<%d> Too small tcp packet(%d) on unknown slot, dropped\r\n", -1, len)); return; } uint16 src_port = ntohs(tcp->src_port); uint16 dest_port = ntohs(tcp->dest_port); BOOL ok = true; BOOL handle_data = false; BOOL initiate_read = false; EnterCriticalSection( &tcp_section ); int t = find_socket( src_port, dest_port ); if(t < 0) { t = alloc_new_socket( src_port, dest_port, ntohl(tcp->ip.dest) ); ok = t >= 0; } if(ok) { D(bug("<%d> write_tcp %d bytes from port %d to port %d\r\n", t, len, src_port, dest_port)); } else { D(bug("<%d> FAILED write_tcp %d bytes from port %d to port %d\r\n", t, len, src_port, dest_port)); } if( ok && ISSET(tcp->flags,RST) ) { D(bug("<%d> RST set, resetting socket\r\n", t)); if( sockets[t].s != INVALID_SOCKET ) { D(bug("<%d> doing an extra shutdown (ie4)\r\n", t)); _shutdown( sockets[t].s, SD_BOTH ); } free_socket( t ); ok = false; } if(ok) { D(bug("<%d> State machine start = %s\r\n", t, STATENAME(sockets[t].state))); // always update receive window sockets[t].mac_window = ntohs(tcp->window); int header_len = tcp->header_len >> 2; int option_bytes = header_len - 20; char *data = (char *)tcp + sizeof(tcp_t) + option_bytes; int dlen = len - sizeof(tcp_t) - option_bytes; if( !ISSET(tcp->flags,ACK) ) { D(bug("<%d> ACK not set\r\n", t)); } if( ISSET(tcp->flags,SYN) ) { D(bug("<%d> SYN set\r\n", t)); // Note that some options are valid even if there is no SYN. // I don't care about those however. uint32 new_mss; process_options( t, (uint8 *)data - option_bytes, option_bytes, new_mss ); if(new_mss) { sockets[t].mac_mss = (int)new_mss; if( new_mss < sockets[t].buffers_read[0].len ) { sockets[t].buffers_read[0].len = new_mss; } D(bug("<%d> Max segment size set to %d\r\n", t, new_mss)); } } if( ISSET(tcp->flags,FIN) ) { D(bug("<%d> FIN set\r\n", t)); } // The sequence number Mac expects to see next time. sockets[t].mac_ack = ntohl(tcp->ack); D(bug("<%d> From Mac: Seq=%d, Ack=%d, window=%d, router Seq=%d\r\n", t, ntohl(tcp->seq), sockets[t].mac_ack, sockets[t].mac_window, sockets[t].seq_out)); if( sockets[t].stream_to_mac_stalled_until && sockets[t].mac_ack == sockets[t].seq_out && (sockets[t].state == ESTABLISHED || sockets[t].state == CLOSE_WAIT) ) { if( has_mac_read_space(t) ) { initiate_read = true; sockets[t].stream_to_mac_stalled_until = 0; D(bug("<%d> read resumed, mac can accept more data\r\n", t)); } } switch( sockets[t].state ) { case CLOSED: sockets[t].src_port = src_port; sockets[t].dest_port = dest_port; sockets[t].ip_src = ntohl(tcp->ip.src); sockets[t].ip_dest = ntohl(tcp->ip.dest); if( ISSET(tcp->flags,SYN) ) { sockets[t].seq_out = 0x00000001; sockets[t].seq_in = ntohl(tcp->seq) + 1; _WSAResetEvent( sockets[t].ev ); if( SOCKET_ERROR == _WSAEventSelect( sockets[t].s, sockets[t].ev, FD_CONNECT | FD_CLOSE ) ) { D(bug("<%d> WSAEventSelect() failed with error code %d\r\n", t, _WSAGetLastError())); } D(bug("<%d> connecting local port %d to remote %s:%d\r\n", t, src_port, _inet_ntoa(sockets[t].from.sin_addr), dest_port)); sockets[t].state = LISTEN; if( _WSAConnect( sockets[t].s, (const struct sockaddr *)&sockets[t].from, sockets[t].from_len, NULL, NULL, NULL, NULL ) == SOCKET_ERROR ) { int connect_error = _WSAGetLastError(); if( connect_error == WSAEWOULDBLOCK ) { D(bug("<%d> WSAConnect() i/o pending.\r\n", t)); } else { D(bug("<%d> WSAConnect() failed with error %d.\r\n", t, connect_error)); } } else { D(bug("<%d> WSAConnect() ok.\r\n", t)); } } else { if( ISSET(tcp->flags,FIN) ) { D(bug("<%d> No SYN but FIN on a closed socket.\r\n", t)); free_socket(t); } else { D(bug("<%d> No SYN on a closed socket. resetting.\r\n", t)); free_socket(t); } } break; case LISTEN: // handled in connect callback break; case SYN_SENT: if( ISSET(tcp->flags,SYN) && ISSET(tcp->flags,ACK) ) { sockets[t].seq_in = ntohl(tcp->seq) + 1; tcp_reply( ACK, t ); sockets[t].state = ESTABLISHED; initiate_read = true; sockets[t].accept_more_data_from_mac = true; sockets[t].time_wait = 0; } else if( ISSET(tcp->flags,SYN) ) { sockets[t].seq_in = ntohl(tcp->seq) + 1; tcp_reply( ACK|SYN, t ); sockets[t].seq_out++; sockets[t].state = SYN_RCVD; sockets[t].time_wait = 0; } else if( ISSET(tcp->flags,ACK) ) { // What was the bright idea here. D(bug("<%d> State is SYN_SENT, but got only ACK from Mac??\r\n", t)); sockets[t].state = FINWAIT_2; sockets[t].time_wait = 0; } break; case SYN_RCVD: if( ISSET(tcp->flags,ACK) ) { sockets[t].state = ESTABLISHED; handle_data = true; initiate_read = true; sockets[t].accept_more_data_from_mac = true; } break; case ESTABLISHED: if( ISSET(tcp->flags,FIN) ) { sockets[t].seq_in++; tcp_reply( ACK, t ); _shutdown( sockets[t].s, SD_SEND ); sockets[t].state = CLOSE_WAIT; } handle_data = true; break; case CLOSE_WAIT: // handled in tcp_read_completion break; case LAST_ACK: if( ISSET(tcp->flags,ACK) ) { D(bug("<%d> LAST_ACK received, socket closed\r\n", t)); free_socket( t ); } break; case FINWAIT_1: if( ISSET(tcp->flags,FIN) && ISSET(tcp->flags,ACK) ) { sockets[t].seq_in++; tcp_reply( ACK, t ); if(sockets[t].remote_closed) { _closesocket(sockets[t].s); sockets[t].s = INVALID_SOCKET; } else { _shutdown( sockets[t].s, SD_SEND ); } sockets[t].state = TIME_WAIT; sockets[t].time_wait = GetTickCount() + 2 * sockets[t].msl; } else if( ISSET(tcp->flags,FIN) ) { sockets[t].seq_in++; tcp_reply( ACK, t ); if(sockets[t].remote_closed) { _closesocket(sockets[t].s); sockets[t].s = INVALID_SOCKET; } else { _shutdown( sockets[t].s, SD_SEND ); } sockets[t].state = CLOSING; } else if( ISSET(tcp->flags,ACK) ) { sockets[t].state = FINWAIT_2; } break; case FINWAIT_2: if( ISSET(tcp->flags,FIN) ) { sockets[t].seq_in++; tcp_reply( ACK, t ); if(sockets[t].remote_closed) { _closesocket(sockets[t].s); sockets[t].s = INVALID_SOCKET; } else { _shutdown( sockets[t].s, SD_SEND ); } sockets[t].state = TIME_WAIT; sockets[t].time_wait = GetTickCount() + 2 * sockets[t].msl; } break; case CLOSING: if( ISSET(tcp->flags,ACK) ) { sockets[t].state = TIME_WAIT; sockets[t].time_wait = GetTickCount() + 2 * sockets[t].msl; } break; case TIME_WAIT: // Catching stray packets: wait MSL * 2 seconds, -> CLOSED // Timer already set since we might not get here at all. // I'm using exceptionally low MSL value (5 secs). D(bug("<%d> time wait, datagram discarded\r\n", t)); break; } // The "t" descriptor may already be freed. However, it's safe // to peek the state value inside the critical section. D(bug("<%d> State machine end = %s\r\n", t, STATENAME(sockets[t].state))); D(bug("<%d> handle_data=%d, initiate_read=%d\r\n", t, handle_data, initiate_read)); if( handle_data && dlen && sockets[t].accept_more_data_from_mac ) { if( sockets[t].seq_in != ntohl(tcp->seq) ) { D(bug("<%d> dropping duplicate datagram seq=%d, expected=%d\r\n", t, ntohl(tcp->seq), sockets[t].seq_in)); } else { set_ttl( t, tcp->ip.ttl ); struct sockaddr_in to; memset( &to, 0, sizeof(to) ); to.sin_family = AF_INET; to.sin_port = tcp->dest_port; to.sin_addr.s_addr = tcp->ip.dest; D(bug("<%d> sending %d bytes to remote host\r\n", t, dlen)); sockets[t].accept_more_data_from_mac = false; if( dlen > MAX_SEGMENT_SIZE ) { D(bug("<%d> IMPOSSIBLE: b_send() dropped %d bytes! \r\n", t, dlen-MAX_SEGMENT_SIZE)); dlen = MAX_SEGMENT_SIZE; } memcpy( sockets[t].buffers_write[0].buf, data, dlen ); sockets[t].buffers_write[0].len = dlen; sockets[t].bytes_remaining_to_send = dlen; sockets[t].bytes_to_send = dlen; bool send_now = false; if( ISSET(tcp->flags,PSH) ) { send_now = true; } else { // todo -- delayed send send_now = true; } if(send_now) { // Patch ftp server or client address if needed. int lst = 1; bool is_pasv; uint16 ftp_data_port = 0; if(ftp_is_ftp_port(sockets[t].src_port)) { // Local ftp server may be entering to passive mode. is_pasv = true; ftp_parse_port_command( sockets[t].buffers_write[0].buf, dlen, ftp_data_port, is_pasv ); } else if(ftp_is_ftp_port(sockets[t].dest_port)) { // Local ftp client may be using port command. is_pasv = false; ftp_parse_port_command( sockets[t].buffers_write[0].buf, dlen, ftp_data_port, is_pasv ); } if(ftp_data_port) { D(bug("<%d> ftp %s command detected, port %d\r\n", t, (is_pasv ? "SERVER PASV REPLY" : "CLIENT PORT"), ftp_data_port )); // Note: for security reasons, only allow incoming connection from sockets[t].ip_dest lst = alloc_listen_socket( ftp_data_port, sockets[t].ip_dest, 0/*iface*/, true ); if(lst < 0) { D(bug("<%d> no more free slots\r\n", t)); } else { // First start listening (need to know the local name later) tcp_start_listen( lst ); // When t is closed, lst must be closed too. sockets[t].child = lst; l_sockets[lst].parent = t; // Find out the local name struct sockaddr_in name; int namelen = sizeof(name); memset( &name, 0, sizeof(name) ); if( _getsockname( sockets[t].s, (struct sockaddr *)&name, &namelen ) == SOCKET_ERROR ) { D(bug("_getsockname() failed, error=%d\r\n", _WSAGetLastError() )); } ftp_modify_port_command( sockets[t].buffers_write[0].buf, dlen, MAX_SEGMENT_SIZE, ntohl(name.sin_addr.s_addr), ftp_data_port, is_pasv ); sockets[t].buffers_write[0].len = dlen; sockets[t].bytes_remaining_to_send = dlen; // Do not change "bytes_to_send" field as it is used for ack calculation } } // end of ftp patch if(!b_send(t)) { // on error, close the ftp data listening socket if one was created if(lst >= 0) { D(bug("[%d] closing listening port %d after write error\r\n", t, l_sockets[lst].port)); _closesocket( l_sockets[lst].s ); l_sockets[lst].s = INVALID_SOCKET; l_sockets[lst].port = 0; l_sockets[lst].ip = 0; l_sockets[lst].parent = -1; sockets[t].child = -1; } } } } } if(initiate_read) { if(!b_recfrom(t)) { // post icmp error message } } } LeaveCriticalSection( &tcp_section ); }
/* 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; }