这段代码是一个处理FTP数据包的函数,根据不同的FTP控制命令和模式进行相应的处理。具体分析如下:
- 获取TCP头部信息
struct tcp_header *th = dp_packet_l4(pkt);
size_t tcp_hdr_len = TCP_OFFSET(th->tcp_ctl) * 4;
char *tcp_hdr = (char *) th;
通过dp_packet_l4()
函数获取TCP头部信息,并计算TCP头部长度。
- 获取FTP控制命令信息
char ftp_msg[LARGEST_FTP_MSG_OF_INTEREST + 1] = {0};
get_ftp_ctl_msg(pkt, ftp_msg);
调用get_ftp_ctl_msg()
函数,将pkt中的FTP控制命令信息存入ftp_msg中。
- 根据不同的控制命令和模式进行处理
if (!strncasecmp(ftp, FTP_EPRT_CMD, strlen(FTP_EPRT_CMD))) {
// ACTIVE模式
} else {
// PASSIVE模式
}
对于ACTIVE模式,先判断命令是否为EPRT,如果是则继续解析IP地址和端口号,并设置模式为ACTIVE。对于PASSIVE模式,则直接设置模式为PASSIVE。
- 解析IP地址和端口号
if (*ftp != FTP_AF_V6 || isdigit(ftp[1])) {
return CT_FTP_CTL_INVALID;
}
/* Jump over delimiter. */
ftp += 2;
memset(&ip6_addr, 0, sizeof ip6_addr);
char *ip_addr_start = ftp;
*addr_offset_from_ftp_data_start = ip_addr_start - ftp_msg;
ftp = skip_ipv6_digits(ftp);
*ftp = 0;
*addr_size = ftp - ip_addr_start;
int rc2 = inet_pton(AF_INET6, ip_addr_start, &ip6_addr);
if (rc2 != 1) {
return CT_FTP_CTL_INVALID;
}
ftp++;
对于ACTIVE模式,先判断IP地址是否为IPv6类型,并跳过分隔符。然后通过inet_pton()
函数将IP地址转换为二进制格式,存储在ip6_addr
中。
char *save_ftp = ftp;
ftp = terminate_number_str(ftp, MAX_EXT_FTP_PORT_DGTS);
if (!ftp) {
return CT_FTP_CTL_INVALID;
}
int value;
if (!str_to_int(save_ftp, 10, &value)) {
return CT_FTP_CTL_INVALID;
}
if (value > CT_MAX_L4_PORT) {
return CT_FTP_CTL_INVALID;
}
uint16_t port_hs = value;
ovs_be16 port = htons(port_hs);
接着解析端口号,并将其转换为网络字节序存储在port
中。
- 根据模式获取地址
switch (*mode) {
case CT_FTP_MODE_ACTIVE:
*v6_addr_rep = conn_for_expectation->rev_key.dst.addr;
if (memcmp(&ip6_addr, &v6_addr_rep->ipv6_aligned, sizeof ip6_addr) &&
memcmp(&ip6_addr, &conn_for_expectation->key.src.addr.ipv6_aligned,
sizeof ip6_addr)) {
return CT_FTP_CTL_INVALID;
}
break;
case CT_FTP_MODE_PASSIVE:
*v6_addr_rep = conn_for_expectation->key.dst.addr;
break;
case CT_TFTP_MODE:
default:
OVS_NOT_REACHED();
}
根据模式获取地址,对于ACTIVE模式,从期望连接的反向地址中获取;对于PASSIVE模式,则从期望连接的目标地址中获取。
- 创建期望连接
expectation_create(ct, port, conn_for_expectation,
!!(pkt->md.ct_state & CS_REPLY_DIR), false, false);
最后调用expectation_create()
函数创建期望连接。