📄 tcpip.cc
字号:
tcp->th_win = htons(window);else tcp->th_win = htons(1024 * (myttl % 4 + 1)); /* Who cares *//* Urgent pointer */if (urp) tcp->th_urp = htons(urp);/* And the options */if (tcpoptlen) memcpy((u8*)tcp + sizeof(struct tcp_hdr), tcpopt, tcpoptlen);/* We should probably copy the data over too */if (data && datalen) memcpy((u8*)tcp + sizeof(struct tcp_hdr) + tcpoptlen, data, datalen);#if STUPID_SOLARIS_CHECKSUM_BUGtcp->th_sum = sizeof(struct tcp_hdr) + tcpoptlen + datalen; #elsetcp->th_sum = magic_tcpudp_cksum(source, victim, IPPROTO_TCP, sizeof(struct tcp_hdr) + tcpoptlen + datalen, (char *) tcp);#endifif ( o.badsum ) --tcp->th_sum; fill_ip_raw(ip, packetlen, ipopt, ipoptlen, tos, ipid, df?IP_DF:0, myttl, IPPROTO_TCP, source, victim); *outpacketlen = packetlen; return packet;}/* You need to call sethdrinclude(sd) on the sending sd before calling this */int send_tcp_raw( int sd, struct eth_nfo *eth, const struct in_addr *source, const struct in_addr *victim, int ttl, bool df, u8* ipops, int ipoptlen, u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags,u16 window, u16 urp, u8 *options, int optlen, char *data, u16 datalen) { unsigned int packetlen; int res = -1; u8 *packet = build_tcp_raw(source, victim, ttl, get_random_u16(), IP_TOS_DEFAULT, df, ipops, ipoptlen, sport, dport, seq, ack, reserved, flags, window, urp, options, optlen, data, datalen, &packetlen); if (!packet) return -1; res = send_ip_packet(sd, eth, packet, packetlen); free(packet); return res;}/* Create and send all fragments of a pre-built IPv4 packet * Minimal MTU for IPv4 is 68 and maximal IPv4 header size is 60 * which gives us a right to cut TCP header after 8th byte * (shouldn't we inflate the header to 60 bytes too?) */int send_frag_ip_packet(int sd, struct eth_nfo *eth, u8 *packet, unsigned int packetlen, unsigned int mtu){ struct ip *ip = (struct ip *) packet; int headerlen = ip->ip_hl * 4; // better than sizeof(struct ip) unsigned int datalen = packetlen - headerlen; int fdatalen = 0, res = 0; assert(headerlen <= (int) packetlen); assert(headerlen >= 20 && headerlen <= 60); // sanity check (RFC791) assert(mtu > 0 && mtu % 8 == 0); // otherwise, we couldn't set Fragment offset (ip->ip_off) correctly if (datalen <= mtu) { error("Warning: fragmentation (mtu=%i) requested but the payload is too small already (%i)", mtu, datalen); return send_ip_packet(sd, eth, packet, packetlen); } u8 *fpacket = (u8 *) safe_malloc(headerlen + mtu); memcpy(fpacket, packet, headerlen + mtu); ip = (struct ip *) fpacket; // create fragments and send them for (int fragment = 1; fragment * mtu < datalen + mtu; fragment++) { fdatalen = (fragment * mtu <= datalen ? mtu : datalen % mtu); ip->ip_len = htons(headerlen + fdatalen); ip->ip_off = htons((fragment-1) * mtu / 8); if ((fragment-1) * mtu + fdatalen < datalen) ip->ip_off |= htons(IP_MF);#if HAVE_IP_IP_SUM ip->ip_sum = in_cksum((unsigned short *)ip, headerlen);#endif if (fragment > 1) // copy data payload memcpy(fpacket + headerlen, packet + headerlen + (fragment - 1) * mtu, fdatalen); res = send_ip_packet(sd, eth, fpacket, headerlen + fdatalen); if (res == -1) break; } free(fpacket); return res;}static int Sendto(char *functionname, int sd, const unsigned char *packet, int len, unsigned int flags, struct sockaddr *to, int tolen) {struct sockaddr_in *sin = (struct sockaddr_in *) to;int res;int retries = 0;int sleeptime = 0;static int numerrors = 0;do { if ((res = sendto(sd, (const char *) packet, len, flags, to, tolen)) == -1) { int err = socket_errno(); numerrors++; if (o.debugging > 1 || numerrors <= 10) { error("sendto in %s: sendto(%d, packet, %d, 0, %s, %d) => %s", functionname, sd, len, inet_ntoa(sin->sin_addr), tolen, strerror(err)); error("Offending packet: %s", ippackethdrinfo(packet, len)); if (numerrors == 10) { error("Omitting future %s error messages now that %d have been shown. Use -d2 if you really want to see them.", __func__, numerrors); } }#if WIN32 return -1;#else if (retries > 2 || err == EPERM || err == EACCES || err == EADDRNOTAVAIL || err == EINVAL) return -1; sleeptime = 15 * (1 << (2 * retries)); error("Sleeping %d seconds then retrying", sleeptime); fflush(stderr); sleep(sleeptime);#endif } retries++;} while( res == -1); PacketTrace::trace(PacketTrace::SENT, packet, len); return res;}/* Send a pre-built IPv4 packet */int send_ip_packet(int sd, struct eth_nfo *eth, u8 *packet, unsigned int packetlen) { struct sockaddr_in sock; int res; struct ip *ip = (struct ip *) packet; struct tcp_hdr *tcp = NULL; struct udp_hdr *udp; u8 *eth_frame = NULL; eth_t *ethsd; bool ethsd_opened = false; assert(packet); assert( (int) packetlen > 0); // fragmentation requested && packet is bigger than MTU if (o.fragscan && ( packetlen - ip->ip_hl * 4 > (unsigned int) o.fragscan )) return send_frag_ip_packet(sd, eth, packet, packetlen, o.fragscan); if (eth) { eth_frame = (u8 *) safe_malloc(14 + packetlen); memcpy(eth_frame + 14, packet, packetlen); eth_pack_hdr(eth_frame, eth->dstmac, eth->srcmac, ETH_TYPE_IP); if (!eth->ethsd) { ethsd = eth_open_cached(eth->devname); if (!ethsd) fatal("%s: Failed to open ethernet device (%s)", __func__, eth->devname); ethsd_opened = true; } else ethsd = eth->ethsd; res = eth_send(ethsd, eth_frame, 14 + packetlen); PacketTrace::trace(PacketTrace::SENT, packet, packetlen); /* No need to close ethsd due to caching */ free(eth_frame); eth_frame = NULL; return res; } assert(sd >= 0); memset(&sock, 0, sizeof(sock)); sock.sin_family = AF_INET;#if HAVE_SOCKADDR_SA_LEN sock.sin_len = sizeof(sock);#endif /* It is bogus that I need the address and port info when sending a RAW IP packet, but it doesn't seem to work w/o them */ if (packetlen >= 20) { sock.sin_addr.s_addr = ip->ip_dst.s_addr; if (ip->ip_p == IPPROTO_TCP && packetlen >= (unsigned int) ip->ip_hl * 4 + 20) { tcp = (struct tcp_hdr *) ((u8 *) ip + ip->ip_hl * 4); sock.sin_port = tcp->th_dport; } else if (ip->ip_p == IPPROTO_UDP && packetlen >= (unsigned int) ip->ip_hl * 4 + 8) { udp = (struct udp_hdr *) ((u8 *) ip + ip->ip_hl * 4); sock.sin_port = udp->uh_dport; } } /* Equally bogus is that the IP total len and IP fragment offset fields need to be in host byte order on certain BSD variants. I must deal with it here rather than when building the packet, because they should be in NBO when I'm sending over raw ethernet */#if FREEBSD || BSDI || NETBSD || DEC || MACOSX ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off);#endif res = Sendto("send_ip_packet", sd, packet, packetlen, 0, (struct sockaddr *)&sock, (int)sizeof(struct sockaddr_in)); return res;}/* Builds an ICMP packet (including an IP header) by packing the fields with the given information. It allocates a new buffer to store the packet contents, and then returns that buffer. The packet is not actually sent by this function. Caller must delete the buffer when finished with the packet. The packet length is returned in packetlen, which must be a valid int pointer. The id/seq will be converted to network byte order (if it differs from HBO) */u8 *build_icmp_raw(const struct in_addr *source, const struct in_addr *victim, int ttl, u16 ipid, u8 tos, bool df, u8 *ipopt, int ipoptlen, u16 seq, unsigned short id, u8 ptype, u8 pcode, char *data, u16 datalen, u32 *packetlen) {struct ppkt { u8 type; u8 code; u16 checksum; u16 id; u16 seq; u8 data[1500]; /* Note -- first 4-12 bytes can be used for ICMP header */} pingpkt;u32 *datastart = (u32 *) pingpkt.data;int dlen = sizeof(pingpkt.data); int icmplen=0;char *ping = (char *) &pingpkt; pingpkt.type = ptype; pingpkt.code = pcode; if (ptype == 8) /* echo request */ { icmplen = 8; } else if (ptype == 13 && pcode == 0) /* ICMP timestamp req */ { icmplen = 20; memset(datastart, 0, 12); datastart += 12; //datalen -= 12; } else if (ptype == 17 && pcode == 0) /* icmp netmask req */ { icmplen = 12; *datastart++ = 0; //datalen -= 4; } else fatal("Unknown icmp type/code (%d/%d) in %s", ptype, pcode, __func__); if (datalen > 0) { icmplen += MIN(dlen, datalen); memset(datastart, 0, MIN(dlen, datalen)); }/* Fill out the ping packet */ pingpkt.id = htons(id); pingpkt.seq = htons(seq);pingpkt.checksum = 0;pingpkt.checksum = in_cksum((unsigned short *)ping, icmplen);if ( o.badsum ) --pingpkt.checksum;return build_ip_raw(source, victim, IPPROTO_ICMP, ttl, ipid, tos, df, ipopt, ipoptlen, ping, icmplen, packetlen);}/* Builds an IGMP packet (including an IP header) by packing the fields with the given information. It allocates a new buffer to store the packet contents, and then returns that buffer. The packet is not actually sent by this function. Caller must delete the buffer when finished with the packet. The packet length is returned in packetlen, which must be a valid int pointer. */u8 *build_igmp_raw(const struct in_addr *source, const struct in_addr *victim, int ttl, u16 ipid, u8 tos, bool df, u8 *ipopt, int ipoptlen, u8 ptype, u8 pcode, char *data, u16 datalen, u32 *packetlen) { struct { u8 igmp_type; u8 igmp_code; u16 igmp_cksum; u32 var; /* changes between types, unused. usually group address. */ u8 data[1500]; } igmp; u32 *datastart = (u32 *) igmp.data; int dlen = sizeof(igmp.data); int igmplen = 0; char *pkt = (char *) &igmp; igmp.igmp_type = ptype; igmp.igmp_code = pcode; if (ptype == 0x11) { /* Membership Query */ igmplen = 8; } else if (ptype == 0x12) { /* v1 Membership Report */ igmplen = 8; } else if (ptype == 0x16) { /* v2 Membership Report */ igmplen = 8; } else if (ptype == 0x17) { /* v2 Leave Group */ igmplen = 8; } else if (ptype == 0x22) { /* v3 Membership Report */ igmplen = 8; } else { fatal("Unknown igmp type (%d) in %s", ptype, __func__); } if (datalen > 0) { igmplen += MIN(dlen, datalen); memset(datastart, 0, MIN(dlen, datalen)); } igmp.igmp_cksum = 0; igmp.igmp_cksum = in_cksum((unsigned short *)pkt, igmplen); if (o.badsum) --igmp.igmp_cksum; return build_ip_raw(source, victim, IPPROTO_IGMP, ttl, ipid, tos, df, ipopt, ipoptlen, pkt, igmplen, packetlen);}/* A simple function I wrote to help in debugging, shows the important fields of a TCP packet*/int readtcppacket(const u8 *packet, int readdata) {struct ip *ip = (struct ip *) packet;struct tcp_hdr *tcp = (struct tcp_hdr *) (packet + sizeof(struct ip));const unsigned char *data = packet + sizeof(struct ip) + sizeof(struct tcp_hdr);int tot_len;struct in_addr bullshit, bullshit2;char sourcehost[16];int i;int realfrag = 0;if (!packet) { error("%s: packet is NULL!", __func__); return -1; }bullshit.s_addr = ip->ip_src.s_addr; bullshit2.s_addr = ip->ip_dst.s_addr;/* this is gay */realfrag = htons(ntohs(ip->ip_off) & 8191 /* 2^13 - 1 */);tot_len = htons(ip->ip_len);strncpy(sourcehost, inet_ntoa(bullshit), 16);i = 4 * (ntohs(ip->ip_hl) + ntohs(tcp->th_off));if (ip->ip_p== IPPROTO_TCP) { if (realfrag) log_write(LOG_PLAIN, "Packet is fragmented, offset field: %u\n", realfrag); else { log_write(LOG_PLAIN, "TCP packet: %s:%d -> %s:%d (total: %d bytes)\n", sourcehost, ntohs(tcp->th_sport), inet_ntoa(bullshit2), ntohs(tcp->th_dport), tot_len); log_write(LOG_PLAIN, "Flags: "); if (!tcp->th_flags) log_write(LOG_PLAIN, "(none)"); if (tcp->th_flags & TH_RST) log_write(LOG_PLAIN, "RST "); if (tcp->th_flags & TH_SYN) log_write(LOG_PLAIN, "SYN "); if (tcp->th_flags & TH_ACK) log_write(LOG_PLAIN, "ACK "); if (tcp->th_flags & TH_PUSH) log_write(LOG_PLAIN, "PSH "); if (tcp->th_flags & TH_FIN) log_write(LOG_PLAIN, "FIN "); if (tcp->th_flags & TH_URG) log_write(LOG_PLAIN, "URG "); log_write(LOG_PLAIN, "\n"); log_write(LOG_PLAIN, "ipid: %hu ttl: %hu ", ntohs(ip->ip_id), ip->ip_ttl); if (tcp->th_flags & (TH_SYN | TH_ACK)) log_write(LOG_PLAIN, "Seq: %u\tAck: %u\n", (unsigned int) ntohl(tcp->th_seq), (unsigned int) ntohl(tcp->th_ack)); else if (tcp->th_flags & TH_SYN) log_write(LOG_PLAIN, "Seq: %u\n", (unsigned int) ntohl(tcp->th_seq)); else if (tcp->th_flags & TH_ACK) log_write(LOG_PLAIN, "Ack: %u\n", (unsigned int) ntohl(tcp->th_ack)); }}if (readdata && i < tot_len) { log_write(LOG_PLAIN, "Data portion:\n"); while(i < tot_len) { log_write(LOG_PLAIN, "%2X%c", data[i], ((i+1) %16)? ' ' : '\n'); i++; } log_write(LOG_PLAIN, "\n");}return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -