* 新增 enable_kni_v3=1 配置项 * develop_build_release 分支关闭 ASAN 检测 * 修正根据 CMSG 恢复 TCP 链接时没有正确填写 TCP 时间戳启用选项的问题
245 lines
5.6 KiB
C++
245 lines
5.6 KiB
C++
#include <string.h>
|
||
#include <netinet/ip.h>
|
||
#include <netinet/ip6.h>
|
||
#include <linux/tcp.h>
|
||
|
||
#include <tfe_utils.h>
|
||
#include <tfe_pkt_util.h>
|
||
|
||
// always success
|
||
void tfe_pkt_parse_ipv4_header(const void *a_packet, struct pkt_info *pktinfo)
|
||
{
|
||
pktinfo->addr_type = ADDR_TYPE_IPV4;
|
||
|
||
pktinfo->iphdr.v4 = (struct iphdr *)a_packet;
|
||
pktinfo->iphdr_len = pktinfo->iphdr.v4->ihl * 4;
|
||
pktinfo->ip_totlen = ntohs(pktinfo->iphdr.v4->tot_len);
|
||
|
||
pktinfo->tcphdr = (struct tcphdr *)((char *)pktinfo->iphdr.v4 + pktinfo->iphdr_len);
|
||
pktinfo->tcphdr_len = pktinfo->tcphdr->doff * 4;
|
||
|
||
pktinfo->data = (char *)pktinfo->tcphdr + pktinfo->tcphdr_len;
|
||
pktinfo->data_len = pktinfo->ip_totlen - pktinfo->iphdr_len - pktinfo->tcphdr_len;
|
||
|
||
pktinfo->parse_failed = 0;
|
||
}
|
||
|
||
// check pktinfo->parse_failed for status
|
||
void tfe_pkt_parse_ipv6_header(const void *a_packet, struct pkt_info *pktinfo)
|
||
{
|
||
pktinfo->addr_type = ADDR_TYPE_IPV6;
|
||
|
||
pktinfo->iphdr.v6 = (struct ip6_hdr *)a_packet;
|
||
pktinfo->ip_totlen = ntohs(pktinfo->iphdr.v6->ip6_ctlun.ip6_un1.ip6_un1_plen) + sizeof(struct ip6_hdr);
|
||
|
||
uint8_t next_hdr_type = pktinfo->iphdr.v6->ip6_ctlun.ip6_un1.ip6_un1_nxt;
|
||
char *next_hdr_ptr = (char *)pktinfo->iphdr.v6 + sizeof(struct ip6_hdr);
|
||
int skip_len = 0;
|
||
while (1)
|
||
{
|
||
switch(next_hdr_type)
|
||
{
|
||
case IPPROTO_TCP:
|
||
//parse tcphdr
|
||
pktinfo->iphdr_len = next_hdr_ptr - (char *)a_packet;
|
||
|
||
pktinfo->tcphdr = (struct tcphdr *)next_hdr_ptr;
|
||
pktinfo->tcphdr_len = pktinfo->tcphdr->doff * 4;
|
||
|
||
pktinfo->data = (char *)pktinfo->tcphdr + pktinfo->tcphdr_len;
|
||
pktinfo->data_len = pktinfo->ip_totlen - pktinfo->iphdr_len - pktinfo->tcphdr_len;
|
||
|
||
pktinfo->parse_failed = 0;
|
||
return;
|
||
case IPPROTO_HOPOPTS: /* fall through */
|
||
case IPPROTO_ROUTING: /* fall through */
|
||
case IPPROTO_AH: /* fall through */
|
||
case IPPROTO_DSTOPTS: /* fall through */
|
||
skip_len = (*(next_hdr_ptr + 1)) * 8 + 8;
|
||
next_hdr_type = *next_hdr_ptr;
|
||
next_hdr_ptr += skip_len;
|
||
break;
|
||
case IPPROTO_NONE: /* fall through */
|
||
default:
|
||
pktinfo->parse_failed = 1;
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
uint16_t tfe_pkt_checksum_ip(const void *buf, size_t hdr_len)
|
||
{
|
||
unsigned long sum = 0;
|
||
const uint16_t *ip1;
|
||
ip1 = (const uint16_t *)buf;
|
||
while (hdr_len > 1)
|
||
{
|
||
sum += *ip1++;
|
||
if (sum & 0x80000000)
|
||
{
|
||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||
}
|
||
hdr_len -= 2;
|
||
}
|
||
while (sum >> 16)
|
||
{
|
||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||
}
|
||
return (~sum);
|
||
}
|
||
|
||
uint16_t tfe_pkt_checksum_tcp_v4(const void *_buf, size_t len, in_addr_t src_addr, in_addr_t dest_addr)
|
||
{
|
||
const uint16_t *buf = (u_int16_t *)_buf;
|
||
uint16_t *ip_src = (uint16_t *)&src_addr;
|
||
uint16_t *ip_dst = (uint16_t *)&dest_addr;
|
||
uint32_t sum;
|
||
size_t length = len;
|
||
|
||
// Calculate the sum
|
||
sum = 0;
|
||
while (len > 1)
|
||
{
|
||
sum += *buf++;
|
||
if (sum & 0x80000000)
|
||
{
|
||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||
}
|
||
len -= 2;
|
||
}
|
||
|
||
if (len & 1)
|
||
{
|
||
// Add the padding if the packet lenght is odd
|
||
sum += *((uint8_t *)buf);
|
||
}
|
||
|
||
// Add the pseudo-header
|
||
sum += *(ip_src++);
|
||
sum += *ip_src;
|
||
sum += *(ip_dst++);
|
||
sum += *ip_dst;
|
||
sum += htons(IPPROTO_TCP);
|
||
sum += htons(length);
|
||
|
||
// Add the carries
|
||
while (sum >> 16)
|
||
{
|
||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||
}
|
||
|
||
// Return the one's complement of sum
|
||
return ((uint16_t)(~sum));
|
||
}
|
||
|
||
uint16_t tfe_pkt_checksum_tcp_v6(const void *_buf, size_t len, struct in6_addr src_addr, struct in6_addr dest_addr)
|
||
{
|
||
const uint16_t *buf = (u_int16_t *)_buf;
|
||
uint16_t *ip_src = (uint16_t *)&src_addr;
|
||
uint16_t *ip_dst = (uint16_t *)&dest_addr;
|
||
uint32_t sum;
|
||
size_t length = len;
|
||
int i = 0;
|
||
|
||
// Calculate the sum
|
||
sum = 0;
|
||
while (len > 1)
|
||
{
|
||
sum += *buf++;
|
||
if (sum & 0x80000000)
|
||
{
|
||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||
}
|
||
len -= 2;
|
||
}
|
||
|
||
if (len & 1)
|
||
{
|
||
// Add the padding if the packet lenght is odd
|
||
sum += *((uint8_t *)buf);
|
||
}
|
||
|
||
// Add the pseudo-header
|
||
for (i = 0; i < 8; i++)
|
||
{
|
||
sum += *ip_src;
|
||
ip_src++;
|
||
}
|
||
for ( i = 0; i < 8; i++)
|
||
{
|
||
sum += *ip_dst;
|
||
ip_dst++;
|
||
}
|
||
sum += htons(IPPROTO_TCP);
|
||
sum += htons(length);
|
||
|
||
// Add the carries
|
||
while (sum >> 16)
|
||
{
|
||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||
}
|
||
|
||
// Return the one's complement of sum
|
||
return ((uint16_t)(~sum));
|
||
}
|
||
|
||
/*
|
||
* 目的:在 IP 的 Payload ${data} 中查找指定的 tcp ${option}。
|
||
*
|
||
* 已知:
|
||
* 1.所有的 tcp options 所占的存储空间的长度为 ${optlen}
|
||
* 2.${out_opt_buff} 输出缓冲区的最大长度为 ${out_opt_buff_size}
|
||
*
|
||
* 返回值:
|
||
* 1.若找到指定的 tcp ${option} 则返回 1,并将该 tcp ${option} 对应的值拷贝到 ${out_opt_buff} 中,并将拷贝的值所占的存储空间记录到 ${out_optlen} 中
|
||
* 2.若未找到指定的 tcp ${option} 则返回 0
|
||
*/
|
||
int tfe_pkt_find_tcp_option(uint8_t option, char *data, unsigned int opts_total_len, uint8_t *out_opt_len, char *out_opt_buff, unsigned int out_opt_buff_size)
|
||
{
|
||
const uint8_t *op;
|
||
unsigned int i;
|
||
|
||
if (!opts_total_len)
|
||
return 0;
|
||
|
||
op = (uint8_t *)(data + sizeof(struct tcphdr));
|
||
for (i = 0; i < opts_total_len;)
|
||
{
|
||
uint8_t __optlen;
|
||
uint8_t __valuelen;
|
||
|
||
if (op[i] == option)
|
||
{
|
||
if (op[i] < 2)
|
||
{
|
||
*out_opt_len = 0;
|
||
return 1;
|
||
}
|
||
|
||
__optlen = op[i + 1];
|
||
if (__optlen <= 2)
|
||
{
|
||
TFE_LOG_ERROR(g_default_logger, "failed at parse tcp options, tcp option length must be larger than 2, but the value is %u", __optlen);
|
||
return 0;
|
||
}
|
||
|
||
__valuelen = __optlen - 2;
|
||
if (__valuelen > out_opt_buff_size)
|
||
{
|
||
TFE_LOG_ERROR(g_default_logger, "failed at parse tcp options, tcp option length is larger than input buffer");
|
||
return 0;
|
||
}
|
||
|
||
*out_opt_len = __valuelen;
|
||
memcpy(out_opt_buff, &op[i + 2], __valuelen);
|
||
return 1;
|
||
}
|
||
|
||
if (op[i] < 2)
|
||
i++;
|
||
else
|
||
i += op[i + 1] ?: 1;
|
||
}
|
||
|
||
return 0;
|
||
} |