/* * Lower MSS on TCP SYN packets to fix MTU * problems which arise from protocol * encapsulation. */ void mss_fixup (struct buffer *buf, int maxmss) { const struct openvpn_iphdr *pip; int hlen; if (BLEN (buf) < (int) sizeof (struct openvpn_iphdr)) return; verify_align_4 (buf); pip = (struct openvpn_iphdr *) BPTR (buf); hlen = OPENVPN_IPH_GET_LEN (pip->version_len); if (pip->protocol == OPENVPN_IPPROTO_TCP && ntohs (pip->tot_len) == BLEN (buf) && (ntohs (pip->frag_off) & OPENVPN_IP_OFFMASK) == 0 && hlen <= BLEN (buf) && BLEN (buf) - hlen >= (int) sizeof (struct openvpn_tcphdr)) { struct buffer newbuf = *buf; if (buf_advance (&newbuf, hlen)) { struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *) BPTR (&newbuf); if (tc->flags & OPENVPN_TCPH_SYN_MASK) mss_fixup_dowork (&newbuf, (uint16_t) maxmss); } } }
/* * If raw tunnel packet is IPv4, return true and increment * buffer offset to start of IP header. */ bool is_ipv4 (int tunnel_type, struct buffer *buf) { int offset; const struct openvpn_iphdr *ih; verify_align_4 (buf); if (tunnel_type == DEV_TYPE_TUN) { if (BLEN (buf) < (int) sizeof (struct openvpn_iphdr)) return false; offset = 0; } else if (tunnel_type == DEV_TYPE_TAP) { const struct openvpn_ethhdr *eh; if (BLEN (buf) < (int)(sizeof (struct openvpn_ethhdr) + sizeof (struct openvpn_iphdr))) return false; eh = (const struct openvpn_ethhdr *) BPTR (buf); if (ntohs (eh->proto) != OPENVPN_ETH_P_IPV4) return false; offset = sizeof (struct openvpn_ethhdr); } else return false; ih = (const struct openvpn_iphdr *) (BPTR (buf) + offset); if (OPENVPN_IPH_GET_VER (ih->version_len) == 4) return buf_advance (buf, offset); else return false; }
/* * If raw tunnel packet is IPv<X>, return true and increment * buffer offset to start of IP header. */ static bool is_ipv_X( int tunnel_type, struct buffer *buf, int ip_ver ) { int offset; const struct openvpn_iphdr *ih; verify_align_4(buf); if (tunnel_type == DEV_TYPE_TUN) { //tun类型,不包含以太头 if (BLEN(buf) < (int) sizeof(struct openvpn_iphdr)) { return false; } offset = 0; } else if (tunnel_type == DEV_TYPE_TAP) { //tap类型,包含以太头 const struct openvpn_ethhdr *eh; if (BLEN(buf) < (int)(sizeof(struct openvpn_ethhdr) + sizeof(struct openvpn_iphdr))) { return false; } eh = (const struct openvpn_ethhdr *) BPTR(buf); if (ntohs(eh->proto) != (ip_ver == 6 ? OPENVPN_ETH_P_IPV6 : OPENVPN_ETH_P_IPV4)) { //非指定协议,返回false return false; } offset = sizeof(struct openvpn_ethhdr); } else { return false; } //指向ip头部 ih = (const struct openvpn_iphdr *) (BPTR(buf) + offset); /* IP version is stored in the same bits for IPv4 or IPv6 header */ if (OPENVPN_IPH_GET_VER(ih->version_len) == ip_ver) { //为对应ip协议,使buf指向对应的ip头部 return buf_advance(buf, offset); } else { //非对应的ip协议,返回false return false; } }
void ipv4_packet_size_verify(const uint8_t *data, const int size, const int tunnel_type, const char *prefix, counter_type *errors) { if (size > 0) { struct buffer buf; buf_set_read(&buf, data, size); if (is_ipv4(tunnel_type, &buf)) { const struct openvpn_iphdr *pip; int hlen; int totlen; const char *msgstr = "PACKET SIZE INFO"; unsigned int msglevel = D_PACKET_TRUNC_DEBUG; if (BLEN(&buf) < (int) sizeof(struct openvpn_iphdr)) { return; } verify_align_4(&buf); pip = (struct openvpn_iphdr *) BPTR(&buf); hlen = OPENVPN_IPH_GET_LEN(pip->version_len); totlen = ntohs(pip->tot_len); if (BLEN(&buf) != totlen) { msgstr = "PACKET TRUNCATION ERROR"; msglevel = D_PACKET_TRUNC_ERR; if (errors) { ++(*errors); } } msg(msglevel, "%s %s: size=%d totlen=%d hlen=%d errcount=" counter_format, msgstr, prefix, BLEN(&buf), totlen, hlen, errors ? *errors : (counter_type)0); } } }
void mss_fixup_dowork (struct buffer *buf, uint16_t maxmss) { int hlen, olen, optlen; uint8_t *opt; uint16_t *mss; int accumulate; struct openvpn_tcphdr *tc; ASSERT (BLEN (buf) >= (int) sizeof (struct openvpn_tcphdr)); verify_align_4 (buf); tc = (struct openvpn_tcphdr *) BPTR (buf); hlen = OPENVPN_TCPH_GET_DOFF (tc->doff_res); /* Invalid header length or header without options. */ if (hlen <= (int) sizeof (struct openvpn_tcphdr) || hlen > BLEN (buf)) return; for (olen = hlen - sizeof (struct openvpn_tcphdr), opt = (uint8_t *)(tc + 1); olen > 0; olen -= optlen, opt += optlen) { if (*opt == OPENVPN_TCPOPT_EOL) break; else if (*opt == OPENVPN_TCPOPT_NOP) optlen = 1; else { optlen = *(opt + 1); if (optlen <= 0 || optlen > olen) break; if (*opt == OPENVPN_TCPOPT_MAXSEG) { if (optlen != OPENVPN_TCPOLEN_MAXSEG) continue; mss = (uint16_t *)(opt + 2); if (ntohs (*mss) > maxmss) { dmsg (D_MSS, "MSS: %d -> %d", (int) ntohs (*mss), (int) maxmss); accumulate = *mss; *mss = htons (maxmss); accumulate -= *mss; ADJUST_CHECKSUM (accumulate, tc->check); } } } } }
/* * If raw tunnel packet is IPv4, return true and increment * buffer offset to start of IP header. */ bool is_ipv4 (int tunnel_type, struct buffer *buf) { int offset; const struct openvpn_iphdr *ih; verify_align_4 (buf); if (tunnel_type == DEV_TYPE_TUN) { if (BLEN (buf) < (int) sizeof (struct openvpn_iphdr)) return false; offset = 0; } else if (tunnel_type == DEV_TYPE_TAP) { const struct openvpn_ethhdr *eh; if (BLEN (buf) < (int)(sizeof (struct openvpn_ethhdr) + sizeof (struct openvpn_iphdr))) return false; eh = (const struct openvpn_ethhdr *) BPTR (buf); if (ntohs (eh->proto) != OPENVPN_ETH_P_IPV4) return false; offset = sizeof (struct openvpn_ethhdr); } else return false; ih = (const struct openvpn_iphdr *) (BPTR (buf) + offset); if (OPENVPN_IPH_GET_VER (ih->version_len) == 4) { /* struct in_addr x,y; x.s_addr = ih->saddr; y.s_addr = ih->daddr; printf("\n src=%s,dest=%s", inet_ntoa(x),inet_ntoa(y));*/ return buf_advance (buf, offset); } else return false; }