diff --git a/Makefile.in b/Makefile.in index 853b8ca..8f832b2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -55,6 +55,7 @@ LDFLAGS = @LDFLAGS@ # Standard LIBS LIBS = @LIBS@ +LIBS += -lpthread INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ @@ -70,7 +71,7 @@ DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@ @rm -f $@ $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c -CSRC = setsignal.c tcpdump.c util.c +CSRC = setsignal.c tcpdump.c util.c net_common.c LIBNETDISSECT_SRC=\ addrtoname.c \ diff --git a/configure b/configure index a5c1026..f5bd200 100644 --- a/configure +++ b/configure @@ -5631,6 +5631,7 @@ if ${ac_cv_lib_pcap_main+:} false; then : else ac_check_lib_save_LIBS=$LIBS LIBS="-lpcap $LIBS" +LIBS += -lpthread cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ diff --git a/mesa_net.h b/mesa_net.h new file mode 100644 index 0000000..ab46da4 --- /dev/null +++ b/mesa_net.h @@ -0,0 +1,811 @@ +#ifndef _MESA_NET_H_ +#define _MESA_NET_H_ + +#include +#include +#include +#include "netdissect.h" +#include "ip.h" +#include "ip6.h" +#include "tcp.h" +#include "udp.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define BYTE_ALIGNED(n) __attribute__((packed, aligned(n))) + + +#define SENDPACKET_ARP_H 0x1c /* ARP header: 28 bytes */ +#define SENDPACKET_ETH_H 0xe /* Etherner header: 14 bytes */ +#define SENDPACKET_IP_H 0x14 /* IP header: 20 bytes */ +/* See sendpacket-ospf.h for OSPF related header sizes */ +#define SENDPACKET_RIP_H 0x18 /* RIP header base: 24 bytes */ +#define SENDPACKET_TCP_H 0x14 /* TCP header: 20 bytes */ +#define SENDPACKET_UDP_H 0x8 /* UDP header: 8 bytes */ + +/* + * Ethernet packet header prototype. Too many O/S's define this differently. + * Easy enough to solve that and define it here. + */ +#ifndef ETHER_ADDR_LEN +#define ETHER_ADDR_LEN 6 +#endif +#define ETHERTYPE_PUP 0x0200 /* PUP protocol */ +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#define ETHERTYPE_IPv6 0x86dd /* IPv6 protocol */ +#define ETHERTYPE_ARP 0x0806 /* Addr. resolution protocol */ +#define ETHERTYPE_REVARP 0x8035 /* reverse Addr. resolution protocol */ +#define ETHERTYPE_VLAN 0x8100 /* IEEE 802.1Q VLAN tagging */ +#define ETHERTYPE_LOOPBACK 0x9000 /* used to test interfaces */ + +#define ETH_P_MAC_IN_MAC 0x88A8 /* pangu项目借用88a8类型, 用于回流MAC_IN_MAC数据包 */ + +#define ETHERTYPE_PANGU_MAC_IN_MAC 0x88A8 /* 2018-08-16 lijia add, for pangu MAC-in-MAC */ + +#if 0 +#define ETHERTYPE_IP_NET 0x0008 /* IP protocol network order */ +#define ETHERTYPE_IPv6_NET 0xdd86 /* IPv6 protocol network order */ +#define ETHERTYPE_VLAN_NET 0x0081 /* IEEE 802.1Q VLAN tagging network order*/ +#define ETH_P_PPP_SES_NET 0x6488 /* PPPoE session messages network order */ +#define ETH_P_MPLS_UC_NET 0x4788 /* MPLS Unicast traffic network order */ +#define ETH_P_ARP_NET 0x0608 /* Address Resolution packet network order */ +#endif + +#define ETHERNET_HDR_LEN (14) +struct mesa_ethernet_hdr +{ + u_int8_t ether_dhost[ETHER_ADDR_LEN]; /* destination ethernet address */ + u_int8_t ether_shost[ETHER_ADDR_LEN]; /* source ethernet address */ + u_int16_t ether_type; /* packet type ID */ +}BYTE_ALIGNED(1); + + +/* + * IPv4 packet header prototype. + */ +#ifndef IP_RF +#define IP_RF 0x8000 /* reserved fragment flag */ +#endif +#ifndef IP_DF +#define IP_DF 0x4000 /* dont fragment flag */ +#endif +#ifndef IP_MF +#define IP_MF 0x2000 /* more fragments flag */ +#endif +#ifndef IP_OFFMASK +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ +#endif + + +#define IPPROTO_L2TPV3 (115) /* L2TPv3, RFC3931-page17 */ + +struct mesa_ip4_hdr +{ +#if __BYTE_ORDER == __LITTLE_ENDIAN + u_int8_t ip_hl:4, /* header length */ + ip_v:4; /* version */ +#elif __BYTE_ORDER == __BIG_ENDIAN + u_int8_t ip_v:4, /* version */ + ip_hl:4; /* header length */ +#else +#error "Please check " +#endif + u_int8_t ip_tos; /* type of service */ + u_int16_t ip_len; /* total length */ + u_int16_t ip_id; /* identification */ + u_int16_t ip_off; + u_int8_t ip_ttl; /* time to live */ + u_int8_t ip_p; /* protocol */ + u_int16_t ip_sum; /* checksum */ + struct in_addr ip_src, ip_dst; /* source and dest address */ +}; + + +/* + * ARP packet header prototype. Too many O/S's define this differently. + * Easy enough to solve that and define it here. + */ +#define ARPOP_REQUEST 1 /* req to resolve address */ +#define ARPOP_REPLY 2 /* resp to previous request */ +#define ARPOP_REVREQUEST 3 /* req protocol address given hardware */ +#define ARPOP_REVREPLY 4 /* resp giving protocol address */ +#define ARPOP_INVREQUEST 8 /* req to identify peer */ +#define ARPOP_INVREPLY 9 /* resp identifying peer */ + + +#define ARPHRD_ETHER 1 /* ethernet hardware format */ +struct mesa_arp_hdr +{ + u_short ar_hrd; /* format of hardware address */ + + u_short ar_pro; /* format of protocol address */ + u_char ar_hln; /* length of hardware address */ + u_char ar_pln; /* length of protocol addres */ + u_short ar_op; /* operation type */ + + /* + * These should implementation defined but I've hardcoded eth/IP. + */ + u_char ar_sha[6]; /* sender hardware address */ + u_char ar_spa[4]; /* sender protocol address */ + u_char ar_tha[6]; /* target hardware address */ + u_char ar_tpa[4]; /* target protocol address */ +}; + + +/* + * IPv6 packet header prototype, add by LiJia 2012-03-19. + */ +struct mesa_ip6_hdr +{ + u_int8_t ip6_flags[4]; /* version, traffic-class, flow-label */ + u_int16_t ip6_payload_len; /* payload length, not contain header */ + u_int8_t ip6_nxt_hdr; /* next header, same as protocol in IPv4 */ + u_int8_t ip6_hop; /* hop limit, same as TTL in IPv4 */ + struct in6_addr ip6_src; /* source address */ + struct in6_addr ip6_dst; /* dest address */ +}; + + +struct mesa_icmp_echo_hdr{ + unsigned char icmp_type; + unsigned char icmp_code; + unsigned short icmp_cksum; + unsigned short icd_id; + unsigned short icd_seq; + //char echo_data[]; +}; + + +/* + * ICMP packet header prototype. // from libnet-headers.h + */ +struct mesa_icmp_hdr +{ + u_char icmp_type; +/* + * ICMP types. + */ +#ifndef ICMP_ECHOREPLY +#define ICMP_ECHOREPLY 0 +#endif +#ifndef ICMP_UNREACH +#define ICMP_UNREACH 3 +#endif +#ifndef ICMP_SOURCEQUENCH +#define ICMP_SOURCEQUENCH 4 +#endif +#ifndef ICMP_REDIRECT +#define ICMP_REDIRECT 5 +#endif +#ifndef ICMP_ECHO +#define ICMP_ECHO 8 +#endif +#ifndef ICMP_ROUTERADVERT +#define ICMP_ROUTERADVERT 9 +#endif +#ifndef ICMP_ROUTERSOLICIT +#define ICMP_ROUTERSOLICIT 10 +#endif +#ifndef ICMP_TIMXCEED +#define ICMP_TIMXCEED 11 +#endif +#ifndef ICMP_PARAMPROB +#define ICMP_PARAMPROB 12 +#endif +#ifndef ICMP_TSTAMP +#define ICMP_TSTAMP 13 +#endif +#ifndef ICMP_TSTAMPREPLY +#define ICMP_TSTAMPREPLY 14 +#endif +#ifndef ICMP_IREQ +#define ICMP_IREQ 15 +#endif +#ifndef ICMP_IREQREPLY +#define ICMP_IREQREPLY 16 +#endif +#ifndef ICMP_MASKREQ +#define ICMP_MASKREQ 17 +#endif +#ifndef ICMP_MASKREPLY +#define ICMP_MASKREPLY 18 +#endif + u_char icmp_code; +/* + * ICMP codes. + */ +#ifndef ICMP_UNREACH_NET +#define ICMP_UNREACH_NET 0 +#endif +#ifndef ICMP_UNREACH_HOST +#define ICMP_UNREACH_HOST 1 +#endif +#ifndef ICMP_UNREACH_PROTOCOL +#define ICMP_UNREACH_PROTOCOL 2 +#endif +#ifndef ICMP_UNREACH_PORT +#define ICMP_UNREACH_PORT 3 +#endif +#ifndef ICMP_UNREACH_NEEDFRAG +#define ICMP_UNREACH_NEEDFRAG 4 +#endif +#ifndef ICMP_UNREACH_SRCFAIL +#define ICMP_UNREACH_SRCFAIL 5 +#endif +#ifndef ICMP_UNREACH_NET_UNKNOWN +#define ICMP_UNREACH_NET_UNKNOWN 6 +#endif +#ifndef ICMP_UNREACH_HOST_UNKNOWN +#define ICMP_UNREACH_HOST_UNKNOWN 7 +#endif +#ifndef ICMP_UNREACH_ISOLATED +#define ICMP_UNREACH_ISOLATED 8 +#endif +#ifndef ICMP_UNREACH_NET_PROHIB +#define ICMP_UNREACH_NET_PROHIB 9 +#endif +#ifndef ICMP_UNREACH_HOST_PROHIB +#define ICMP_UNREACH_HOST_PROHIB 10 +#endif +#ifndef ICMP_UNREACH_TOSNET +#define ICMP_UNREACH_TOSNET 11 +#endif +#ifndef ICMP_UNREACH_TOSHOST +#define ICMP_UNREACH_TOSHOST 12 +#endif +#ifndef ICMP_UNREACH_FILTER_PROHIB +#define ICMP_UNREACH_FILTER_PROHIB 13 +#endif +#ifndef ICMP_UNREACH_HOST_PRECEDENCE +#define ICMP_UNREACH_HOST_PRECEDENCE 14 +#endif +#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF +#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 +#endif +#ifndef ICMP_REDIRECT_NET +#define ICMP_REDIRECT_NET 0 +#endif +#ifndef ICMP_REDIRECT_HOST +#define ICMP_REDIRECT_HOST 1 +#endif +#ifndef ICMP_REDIRECT_TOSNET +#define ICMP_REDIRECT_TOSNET 2 +#endif +#ifndef ICMP_REDIRECT_TOSHOST +#define ICMP_REDIRECT_TOSHOST 3 +#endif +#ifndef ICMP_TIMXCEED_INTRANS +#define ICMP_TIMXCEED_INTRANS 0 +#endif +#ifndef ICMP_TIMXCEED_REASS +#define ICMP_TIMXCEED_REASS 1 +#endif +#ifndef ICMP_PARAMPROB_OPTABSENT +#define ICMP_PARAMPROB_OPTABSENT 1 +#endif + + u_short icmp_sum; + + union + { + struct + { + u_short id; + u_short seq; + }echo; + +#undef icmp_id +#undef icmp_seq +#define icmp_id hun.echo.id +#define icmp_seq hun.echo.seq + + u_long gateway; + struct + { + u_short pad; + u_short mtu; + }frag; + }hun; + union + { + struct + { + n_time its_otime; + n_time its_rtime; + n_time its_ttime; + }ts; + struct + { + struct ip idi_ip; + /* options and then 64 bits of data */ + }ip; + u_long mask; + char data[1]; + +#undef icmp_mask +#define icmp_mask dun.mask +#undef icmp_data +#define icmp_data dun.data + +#undef icmp_otime +#define icmp_otime dun.ts.its_otime +#undef icmp_rtime +#define icmp_rtime dun.ts.its_rtime +#undef icmp_ttime +#define icmp_ttime dun.ts.its_ttime + }dun; + +}; + +/* + * TCP packet header prototype. + */ +#ifndef TH_FIN +#define TH_FIN 0x01 +#endif +#ifndef TH_SYN +#define TH_SYN 0x02 +#endif +#ifndef TH_RST +#define TH_RST 0x04 +#endif +#ifndef TH_PUSH +#define TH_PUSH 0x08 +#endif +#ifndef TH_ACK +#define TH_ACK 0x10 +#endif +#ifndef TH_URG +#define TH_URG 0x20 +#endif +struct mesa_tcp_hdr +{ + u_int16_t th_sport; /* source port */ + u_int16_t th_dport; /* destination port */ + u_int32_t th_seq; /* sequence number */ + u_int32_t th_ack; /* acknowledgement number */ +#if __BYTE_ORDER == __LITTLE_ENDIAN + u_int8_t th_x2:4, /* (unused) */ + th_off:4; /* data offset */ +#elif __BYTE_ORDER == __BIG_ENDIAN + u_int8_t th_off:4, /* data offset */ + th_x2:4; /* (unused) */ +#else +#error "Please check " +#endif + u_int8_t th_flags; /* control flags */ + u_int16_t th_win; /* window */ + u_int16_t th_sum; /* checksum */ + u_int16_t th_urp; /* urgent pointer */ +}; + + +/* + * UDP packet header prototype. + */ +struct mesa_udp_hdr +{ + u_int16_t uh_sport; /* soure port */ + u_int16_t uh_dport; /* destination port */ + u_int16_t uh_ulen; /* length */ + u_int16_t uh_sum; /* checksum */ +}; + + +#define PPPOE_HDR_LEN (sizeof(struct mesa_pppoe_session_hdr)) +#define PPP_PROTOCOL_PAD (0x0001) +#define PPP_PROTOCOL_IPv4 (0x0021) +#define PPP_PROTOCOL_PAP (0xC023) +#define PPP_PROTOCOL_CHAP (0xC223) +#define PPP_PROTOCOL_IPv6 (0x0057) +#define PPP_COMPRESS_DATA (0x00FD) + +#define PPP_PROTOCOL_LCP (0xC021) +#define PPP_PROTOCOL_CCP (0x80FD) +#define PPP_PROTOCOL_IPCP (0x8021) + +struct mesa_pppoe_session_hdr{ +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ver:4; + unsigned int type:4; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int type:4; + unsigned int ver:4; +#else +#error "Please check " +#endif + unsigned char code; + unsigned short session_id; + unsigned short len; + /* to do: + ppp应该单独作为一层存在, 为了简化处理, 强制将其和PPPOE_SES绑在一起, + 如果需要监听PPP协商过程, 此结构需要改动. + */ + unsigned short ppp_protocol; +}BYTE_ALIGNED(1); + + +struct mesa_ppp_hdr{ + unsigned char address; + unsigned char control; + unsigned short protocol; +}BYTE_ALIGNED(1); + +#define PPP_LCP_CODE_REQUEST (1) +#define PPP_LCP_CODE_ACK (2) +#define PPP_LCP_CODE_NAK (3) +#define PPP_LCP_CODE_REJECT (4) +#define PPP_LCP_CODE_TERMINATE_REQ (5) +#define PPP_LCP_CODE_TERMINATE_ACK (6) + +/* refer to RFC1661 */ +#define PPP_LCP_OPT_RESERVED (0) +#define PPP_LCP_OPT_MAX_RCV_UNIT (1) +#define PPP_LCP_OPT_AUTH_PRO (3) +#define PPP_LCP_OPT_QA_PRO (4) +#define PPP_LCP_OPT_MAGIC (5) +#define PPP_LCP_OPT_PRO_FIELD_COMPRESS (7) +#define PPP_LCP_OPT_ADDR_CTRL_FIELD_COMPRESS (8) + +#define PPP_LCP_OPT_AUTH_PRO_PAP (0xC023) +#define PPP_LCP_OPT_AUTH_PRO_CHAP (0xC223) + +#define PPP_LCP_OPT_AUTH_PRO_CHAP_ALGO_MS_CHAP_V2 (0x81) +#define PPP_LCP_OPT_AUTH_PRO_CHAP_ALGO_CHAP_MD5 (0x05) + + +/* refer to RFC1962 Page6 */ +#define PPP_CCP_OPT_OUI (0) +#define PPP_CCP_OPT_MS_PPC (18) + +struct mesa_ppp_lcp_ack_hdr{ /* RFC1661-Page29 */ + unsigned char code; + unsigned char identifier; + unsigned short length; +}BYTE_ALIGNED(1); + +struct mesa_ppp_ccp_ack_hdr{ /* RFC1661-Page29 */ + unsigned char code; + unsigned char identifier; + unsigned short length; +}BYTE_ALIGNED(1); + +#define PPP_CHAP_CHALLENGE (1) +#define PPP_CHAP_RESPONSE (2) +#define PPP_CHAP_SUCCESS (3) +#define PPP_CHAP_FAILURE (4) + +struct mesa_ppp_chap_hdr{ + unsigned char code; + unsigned char identifier; + unsigned short length; +}BYTE_ALIGNED(1); + +struct mesa_ppp_ipcp_ack_hdr{ + unsigned char code; + unsigned char identifier; + unsigned short length; +}BYTE_ALIGNED(1); + +enum pptp_control_message_type{ + PPTP_CTRL_START_CONN_REQ = 1, + PPTP_CTRL_START_CONN_REPLY = 2, + PPTP_CTRL_STOP_CONN_REQ = 3, + PPTP_CTRL_STOP_CONN_REPLY = 4, + PPTP_CTRL_ECHO_REQ = 5, + PPTP_CTRL_ECHO_REPLY = 6, + PPTP_CTRL_OUT_GO_REQ = 7, + PPTP_CTRL_OUT_GO_REPLY = 8, + PPTP_CTRL_IN_CALL_REQ = 9, + PPTP_CTRL_IN_CALL_REPLY = 10, + PPTP_CTRL_IN_CALL_CONN = 11, + PPTP_CTRL_CALL_CLEAR_REQ = 12, + PPTP_CTRL_CALL_DISCONN_NOTIFY = 13, + PPTP_CTRL_WAN_ERROR_NOTIFY = 14, + PPTP_CTRL_SET_LINK_INFO = 15, +}; + +struct mesa_pptp_control_hdr{ + unsigned short length; /* 全部数据长度, 包括本头部 */ + unsigned short pptp_message_type; + unsigned int magic_cookie; + unsigned short control_message_type; + char ignore_bytes[0]; /* 后续字段暂不关心, 长度也不一定 */ +}; + +struct mesa_vlan_hdr{ + unsigned short pri_cfi_id; + unsigned short type; +}; + +struct mesa_vlan_detail_hdr{ + unsigned int priority:3; + unsigned int del_flag:1; + unsigned int vlan_id:12; + unsigned short type; +}; + +/* 2018-08-28 lijia add, for pangu 项目mac_in_mac回流 */ +struct mesa_mac_in_mac_net_hdr{ + unsigned int route_dir:1; + unsigned int link_id:3; + unsigned int dev_id:6; + unsigned int region_id:5; + unsigned int __pad1:1; + unsigned int encap_type:4; + unsigned int __pad2:20; + unsigned int __pad3:8; +}; + +struct mesa_gre_base_hdr_v0{ +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned char recur:3; + unsigned char strict_src_route_flag:1; + unsigned char seq_flag:1; + unsigned char key_flag:1; + unsigned char route_flag:1; + unsigned char checksum_flag:1; + + unsigned char version:3; + unsigned char flags:5; /* version 0 flags is 5 bit */ +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned char checksum_flag:1; + unsigned char route_flag:1; + unsigned char key_flag:1; + unsigned char seq_flag:1; + unsigned char strict_src_route_flag:1; + unsigned char recur:3; + + unsigned char flags:5; /* version 0 flags is 5 bit */ + unsigned char version:3; +#else +#error "Please check " +#endif + unsigned short protocol; +}; + +struct mesa_gre_base_hdr_v1{ +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned char recur:3; + unsigned char strict_src_route_flag:1; + unsigned char seq_flag:1; + unsigned char key_flag:1; + unsigned char route_flag:1; + unsigned char checksum_flag:1; + + unsigned char version:3; + unsigned char flags:4; /* version 1 flags is 4 bit */ + unsigned char ack_flag:1; + +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned char checksum_flag:1; + unsigned char route_flag:1; + unsigned char key_flag:1; + unsigned char seq_flag:1; + unsigned char strict_src_route_flag:1; + unsigned char recur:3; + + unsigned char ack_flag:1; + unsigned char flags:4; /* version 1 flags is 4 bit */ + unsigned char version:3; +#else +#error "Please check " +#endif + unsigned short protocol; +}; + +#define GRE_SRE_MAX_LEN (256) /* 长度最长为一个字节, 256 */ +struct gre_source_route_entry_hdr{ + unsigned short address_family; + unsigned char sre_offset; + unsigned char sre_length; + unsigned char sre_entry_list[GRE_SRE_MAX_LEN]; +}; + +/* 所有可能的值均在, 需要根据mesa_gre_base_hdr各个bit的值, 判断是否含有如下值 */ +struct mesa_gre_extend_hdr{ + unsigned short checksum; //version0 + unsigned short offset; //version0, if checksum present, then offset also present + unsigned short payload_len; //version1 + unsigned short call_id; //version1 + unsigned int key; //version0 + unsigned int seq_num; //version0 and version1 + unsigned int ack_num; //version1 + //struct gre_source_route_entry_hdr sre_list; +}; + +struct mesa_gre_hdr{ + /* version0和version1的头部中, version字段时一致的, 其他有小区别, 默认使用v0方式解析 */ + struct mesa_gre_base_hdr_v0 gre_base; + struct mesa_gre_extend_hdr gre_extend; +}; + + +#define MPLS_LABEL_MASK (0xFFFFF000) +#define MPLS_EXP_MASK (0x00000E00) +#define MPLS_BLS_MASK (0x00000100) +#define MPLS_TTL_MASK (0x000000FF) +struct mesa_mpls_hdr{ +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned short mpls_label_low; + unsigned char mpls_bls:1; /* bottom of label stack */ + unsigned char mpls_exp:3; + unsigned char mpls_label_high:4; + unsigned char mpls_ttl; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned char mpls_ttl; + unsigned char mpls_label_high:4; + unsigned char mpls_exp:3; + unsigned char mpls_bls:1; /* bottom of label stack */ + unsigned short mpls_label_low; +#else +#error "Please check " +#endif +}; + +#define L2TP_REGISTERED_IP_PRO (115) +#define L2TP_REGISTERED_PORT (1701) + +#define L2TP_HDR_TYPE_DATA (0) +#define L2TP_HDR_TYPE_CONTROL (1) + +struct l2tp_hdr_v2{ +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned char priority:1; + unsigned char offset_present:1; + unsigned char reserved2:1; + unsigned char seq_present:1; + unsigned char reserved1:2; + unsigned char length_present:1; + unsigned char type:1; + + unsigned char version:4; + unsigned char reserved3:4; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned char reserved3:4; + unsigned char version:4; + + unsigned char type:1; + unsigned char length_present:1; + unsigned char reserved1:2; + unsigned char seq_present:1; + unsigned char reserved2:1; + unsigned char offset_present:1; + unsigned char priority:1; +#else +#error "Please check " +#endif +}; + +/* refer to RFC2661-Page12 */ +#define L2TP_CTRL_MSG_RESERVED0 (0) +#define L2TP_CTRL_MSG_SCCRQ (1) +#define L2TP_CTRL_MSG_SCCRP (2) +#define L2TP_CTRL_MSG_SCCCN (3) +#define L2TP_CTRL_MSG_STOP_CCN (4) +#define L2TP_CTRL_MSG_RESERVED5 (5) +#define L2TP_CTRL_MSG_HELLO (6) +#define L2TP_CTRL_MSG_OCRQ (7) +#define L2TP_CTRL_MSG_OCRP (8) +#define L2TP_CTRL_MSG_OCCN (9) +#define L2TP_CTRL_MSG_ICRQ (10) +#define L2TP_CTRL_MSG_ICRP (11) +#define L2TP_CTRL_MSG_ICCN (12) +#define L2TP_CTRL_MSG_RESERVED13 (13) +#define L2TP_CTRL_MSG_CDN (14) +#define L2TP_CTRL_MSG_WEN (15) +#define L2TP_CTRL_MSG_SLI (16) + +#define L2TP_AVP_GET_LEN(u) (ntohs(u) & 0x3F) +struct l2tp_avp{ + unsigned short M_H_rsvd_len_union; + unsigned short vendor_id; + unsigned short attribute_type; +}BYTE_ALIGNED(1); + +/* RFC2408-Page23 */ +#define ISAKMP_PAYLOAD_TYPE_NONE (0) +#define ISAKMP_PAYLOAD_TYPE_SA (1) +#define ISAKMP_PAYLOAD_TYPE_PROPOSAL (2) +#define ISAKMP_PAYLOAD_TYPE_TRANSFORM (3) +#define ISAKMP_PAYLOAD_TYPE_KEY_EXCHANGE (4) +#define ISAKMP_PAYLOAD_TYPE_ID (5) +#define ISAKMP_PAYLOAD_TYPE_CERT (6) +#define ISAKMP_PAYLOAD_TYPE_CR (7) +#define ISAKMP_PAYLOAD_TYPE_HASH (8) +#define ISAKMP_PAYLOAD_TYPE_SIG (9) +#define ISAKMP_PAYLOAD_TYPE_NONCE (10) +#define ISAKMP_PAYLOAD_TYPE_NOTIFY (11) +#define ISAKMP_PAYLOAD_TYPE_DELETE (12) +#define ISAKMP_PAYLOAD_TYPE_VENDOR_ID (13) +#define ISAKMP_PAYLOAD_TYPE_RESERVED_BEGIN (14) /* 14 - 127 */ +#define ISAKMP_PAYLOAD_TYPE_RESERVED_END (127) /* 14 - 127 */ +#define ISAKMP_PAYLOAD_TYPE_PRIVATE_USE_BEGIN (128) /* 128-255 */ +#define ISAKMP_PAYLOAD_TYPE_PRIVATE_USE_END (255) /* 128-255 */ + +/* RFC2408-Page23 */ +#define ISAKMP_EXCHANGE_TYPE_NONE (0) +#define ISAKMP_EXCHANGE_TYPE_BASE (1) +#define ISAKMP_EXCHANGE_TYPE_ID_PROT (2) /* RFC-2409 page8, main mode is instantiation os ISAKMP Identity Protect Exchange */ +#define ISAKMP_EXCHANGE_TYPE_AUTH (3) +#define ISAKMP_EXCHANGE_TYPE_AGGRESS (4)/* RFC-2409 page8, Aggressive mode is instantiation os ISAKMP Aggressive Exchange */ +#define ISAKMP_EXCHANGE_TYPE_INFO (5) +#define ISAKMP_EXCHANGE_TYPE_FEATURE_USE_BEGIN (6) /* 6-31的值暂不可用 */ +#define ISAKMP_EXCHANGE_TYPE_FEATURE_USE_END (31) /* 6-31的值暂不可用 */ + +struct mesa_isakmp_hdr{ /* RFC2408-Page22 */ + unsigned long long init_cookie; + unsigned long long resp_cookie; + unsigned char next_payload; +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned char minor_version:4; + unsigned char major_version:4; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned char major_version:4; + unsigned char minor_version:4; +#else +#error "Please check " +#endif + + unsigned char exchange_type; + unsigned char flags; + unsigned int message_id; + unsigned int length; +}; + +struct mesa_isakmp_payload_hdr{ /* RFC2408-Page22 */ + unsigned char next_payload; + unsigned char reserver; + unsigned short payload_len; +}; + +#define GTP_MSG_TYPE_T_PDU (0xFF) + +struct gtp_hdr{ +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned char flags; + unsigned char msg_type; + unsigned short len; + unsigned int teid; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int teid; + unsigned short len; + unsigned char msg_type; + unsigned char flags; +#else +#error "Please check " +#endif +}; + +#define MAX_ADDR_TYPE_STRING_LEN (64) +#define MAX_ADDR_LIST_STRING_LEN (2048) +#define MAX_ADDR_EMBED_LAYER_NUM (20) /* 最大地址嵌套层数 */ +#define MAX_ADDR_BIN_VALUE_LEN (40) /* paddr实际内容最大长度, 目前是tuple4v6最长 */ + +/* 串联模式下, 记录MAC地址用于发包 */ +struct packet_io_mac_addr{ + struct mesa_ethernet_hdr eth_hdr; + char route_dir; + char __pad__; /* 整体结构8字节对齐 */ +}; + +unsigned char net_layer_to_ipv4_protocol(int addr_type); +unsigned char net_layer_to_ipv6_protocol(int addr_type); +unsigned short net_layer_to_ethernet_protocol(int addr_type); +int net_common_build_send_mac(unsigned char *buf, const struct mesa_ethernet_hdr *raw_eth_hdr, int addr_type, int dir_reverse, int net_topology_mode); +int net_common_adjust_forward_mac(struct mesa_ethernet_hdr *raw_eth_hdr,int net_topology_mode); +const void *MESA_net_jump_to_layer(const void *raw_data, int raw_layer_type, int expect_layer_type); +const void *MESA_net_jump_to_layer_greedy(const void *raw_data, int raw_layer_type, int expect_layer_type); +char MESA_ascii_to_hex(char ascii); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/net_common.c b/net_common.c new file mode 100644 index 0000000..4a80624 --- /dev/null +++ b/net_common.c @@ -0,0 +1,826 @@ + +#include +#include +#include +#include +#include +#include + +#include "netdissect-stdinc.h" +#include "netdissect.h" +#include "stream_base.h" +#include "mesa_net.h" +#include "ip.h" +#include "ip6.h" +#include "tcp.h" +#include "udp.h" +#include "ppp.h" + + + +#ifdef __cplusplus +extern "C" { +#endif + +static int eth_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type); +static int vlan8021q_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type); +static int ipv4_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type); +static int ipv6_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type); + +static int treat_vlan_as_mac_in_mac_sw = 1; + +/* ascii字符转16进制 */ +char MESA_ascii_to_hex(char ascii) +{ + char c = 0; + + switch(ascii) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + c = ascii - 0x30; + break; + + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + c = 10 + ascii - 0x61; + break; + + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + c = 10 + ascii - 0x41; + break; + } + + return c; +} + + + +static int arp_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type) +{ + /* arp协议不承载任何上层其他协议 */ + return -1; +} + + +static int gtp_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type) +{ + const struct gtp_hdr *gh = (struct gtp_hdr *)raw_data; + int opt_len = 0; /* 可选项长度 */ + const unsigned char *next_ip_layer_hdr; + int skip_len; + + if(ADDR_TYPE_GPRS_TUNNEL == expect_layer_type){ + return 0; + } + + if(gh->flags & 0x2){ + opt_len += sizeof(int); /* sequence */ + } + + next_ip_layer_hdr = (unsigned char *)raw_data + opt_len + sizeof(struct gtp_hdr); + + if((*next_ip_layer_hdr & 0x40) == 0x40){ + skip_len = ipv4_jump_to_layer((char *)next_ip_layer_hdr, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type); + }else if((*next_ip_layer_hdr & 0x60) == 0x60){ + skip_len = ipv6_jump_to_layer((char *)next_ip_layer_hdr, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type); + }else{ + ////sapp_runtime_log(20, "TODO: jmp unsupport type in GTP, 0x%x!\n", (*next_ip_layer_hdr)); + return -1; + } + + return opt_len + sizeof(struct gtp_hdr) + skip_len; +} + +static int udp_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type) +{ + const struct mesa_udp_hdr *uh = (const struct mesa_udp_hdr *)raw_data; + unsigned short usport, udport; + int skip_len; + + if(ADDR_TYPE_UDP == expect_layer_type){ + return 0; + } + + usport = ntohs(uh->uh_sport); + udport = ntohs(uh->uh_dport); + + if((2152 == usport) && (2152 == udport)){ + skip_len = gtp_jump_to_layer(raw_data+sizeof(struct mesa_udp_hdr), ADDR_TYPE_UDP, expect_layer_type); + }else if((3544 == usport) || (3544 == udport)){ + ; + //TODO + //skip_len = teredo_jump_to_layer(raw_data+sizeof(struct mesa_udp_hdr), ADDR_TYPE_UDP, expect_layer_type); + }else{ + /* 其他UDP类型不支持再跳转 */ + return -1; + } + + return skip_len + sizeof(struct mesa_udp_hdr); +} + +static int ipv4_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type) +{ + struct ip *p_ip_hdr = (struct ip *)raw_data; + int skip_len = 0; + int ip_hdr_len = IP_HL(p_ip_hdr) * 4; + //const char *next_layer_data = raw_data + ip_hdr_len; + + if(raw_layer_type == expect_layer_type){ + return 0; + } + + switch(p_ip_hdr->ip_p){ + case IPPROTO_TCP: + if(ADDR_TYPE_TCP == expect_layer_type){ + skip_len = 0; + break; + }else{ + skip_len = -1; /* tcp 层之上不承载其他协议 */ + } + break; + + case IPPROTO_UDP: + if(ADDR_TYPE_UDP == expect_layer_type){ + skip_len = 0; + break; + }else{ + skip_len = udp_jump_to_layer(raw_data+ip_hdr_len, ADDR_TYPE_UDP, expect_layer_type); + } + break; + + case IPPROTO_IPV6: + if(__ADDR_TYPE_IP_PAIR_V6 == expect_layer_type){ + skip_len = 0; + break; + }else{ + skip_len = ipv6_jump_to_layer(raw_data+ip_hdr_len, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type); + } + break; + + default: + skip_len = -1; + break; + } + + if(skip_len < 0){ + return -1; + } + + return skip_len + sizeof(struct ip); +} + +static int ipv6_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type) +{ + const struct mesa_ip6_hdr *a_packet = (const struct mesa_ip6_hdr *)raw_data; + UINT8 next_hdr_type = a_packet->ip6_nxt_hdr; + UINT8 *next_hdr_ptr = (UINT8 *)a_packet + sizeof(struct mesa_ip6_hdr); + int skip_len = 0; + int offset_to_ip6 = 0; + + if(raw_layer_type == expect_layer_type){ + return 0; + } + + while(1){ + offset_to_ip6 = 0; + switch(next_hdr_type) + { + case 0: //NEXTHDR_HOP: + case 43://NEXTHDR_ROUTING: + case 51://NEXTHDR_AUTH: + case 60://NEXTHDR_DEST: + offset_to_ip6 = (*(next_hdr_ptr + 1))*8 + 8; /* 选项长度以8字节为单位 */ + break; + + case 4://NEXTHDR_IPIP: + if(__ADDR_TYPE_IP_PAIR_V4 == expect_layer_type){ + skip_len = next_hdr_ptr - (UINT8 *)raw_data; + }else{ + skip_len = ipv4_jump_to_layer((const char *)next_hdr_ptr, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type); + if(skip_len < 0){ + return -1; + }else{ + return skip_len + next_hdr_ptr - (UINT8 *)raw_data; + } + } + goto done; + break; + + case 59://NEXTHDR_NONE: + skip_len = -1; + goto done; + break; + + case 58://NEXTHDR_ICMP: /* IMCP不再承载其他协议 */ + skip_len = -1; + goto done; + break; + + case 6://NEXTHDR_TCP: + if(ADDR_TYPE_TCP == expect_layer_type){ + skip_len = next_hdr_ptr - (UINT8 *)raw_data; + }else{ + skip_len = -1; + } + goto done; + break; + + case 17://NEXTHDR_UDP: + if(ADDR_TYPE_UDP == expect_layer_type){ + skip_len = next_hdr_ptr - (UINT8 *)raw_data; + }else{ + skip_len = -1; + } + goto done; + break; + + case 44:///NEXTHDR_FRAGMENT: + offset_to_ip6 = 8; // 8 == sizeof(struct ipv6_frag_hdr); + break; + + case 50://NEXTHDR_ESP: + skip_len = -1; + goto done; + + default: + printf("TODO:jmp Unknown IPv6 header type:0x%x!\n", next_hdr_type); + skip_len = -1; + goto done; + break; + } + + next_hdr_type = *next_hdr_ptr; + next_hdr_ptr += offset_to_ip6; + } + +done: + if(skip_len < 0){ + return -1; + } + + return skip_len; +} + +static int ppp_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type) +{ + int skip_len = 0; + struct mesa_pppoe_session_hdr *pppoe_ses_hdr; + char *next_hdr; + + if(raw_layer_type == expect_layer_type){ + return 0; + } + pppoe_ses_hdr = (struct mesa_pppoe_session_hdr *)raw_data; + next_hdr = (char *)raw_data + sizeof(struct mesa_pppoe_session_hdr); + + switch(ntohs(pppoe_ses_hdr->ppp_protocol)){ + case PPP_PROTOCOL_IPv4: + if(__ADDR_TYPE_IP_PAIR_V4 == expect_layer_type){ + break; + }else{ + skip_len = ipv4_jump_to_layer(next_hdr, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type); + } + break; + + case PPP_IPV6: + if(__ADDR_TYPE_IP_PAIR_V6 == expect_layer_type){ + break; + }else{ + skip_len = ipv6_jump_to_layer(next_hdr, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type); + } + break; + + case PPP_COMP: + case PPP_CCP: + case PPP_IPCP: + case PPP_PAP: + case PPP_CHAP: + case 0xC025: ///PPP_LQR: + case PPP_PROTOCOL_LCP: + + /* 不承载应用层协议 */ + skip_len = -1; + break; + + default: + printf("TODO: jmp unsupport ppp pro:0x%x!\n", ntohs(pppoe_ses_hdr->ppp_protocol)); + break; + + } + + if(skip_len < 0){ + return -1; + } + + return skip_len + sizeof(struct mesa_pppoe_session_hdr); +} + + +static int mpls_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type) +{ + int skip_len = 0; + const struct mesa_mpls_hdr *mpls_hdr = (const struct mesa_mpls_hdr *)raw_data; + const char *next_layer_data = raw_data + sizeof(struct mesa_mpls_hdr); + + if(raw_layer_type == expect_layer_type){ + return 0; + } + + if(0 == mpls_hdr->mpls_bls){ /* 非MPLS栈底, 递归调用自身 */ + return mpls_jump_to_layer(next_layer_data, ADDR_TYPE_MPLS, expect_layer_type) + sizeof(struct mesa_mpls_hdr); + } + + /* MPLS没有字段标识下一层是什么, 靠猜测下一层的IP类型 */ + if((*next_layer_data & 0x40) == 0x40){ + skip_len = ipv4_jump_to_layer(next_layer_data, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type); + }else if((*next_layer_data & 0x60) == 0x60){ + skip_len = ipv6_jump_to_layer(next_layer_data, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type); + }else{ + //sapp_runtime_log(20, "TODO: jmp unsupport type in MPLS, 0x%x!\n", (unsigned char)(*next_layer_data)); + return -1; + } + + return skip_len + sizeof(struct mesa_mpls_hdr); /* mpls header is 4 byte */ +} + +static int __common_eth_type_dispatch(UINT16 eth_type, const char *next_layer_data, int raw_layer_type, int expect_layer_type) +{ + int skip_len = 0; + + switch(eth_type){ + case ETH_P_ARP: + if(ADDR_TYPE_ARP == expect_layer_type){ + break; + }else{ + skip_len = arp_jump_to_layer(next_layer_data, ADDR_TYPE_ARP, expect_layer_type); + } + break; + + case ETH_P_8021Q: + if(ADDR_TYPE_VLAN == expect_layer_type){ + break; + }else{ + if(treat_vlan_as_mac_in_mac_sw){ + skip_len = eth_jump_to_layer(next_layer_data, ADDR_TYPE_MAC, expect_layer_type); + }else{ + skip_len = vlan8021q_jump_to_layer(next_layer_data, ADDR_TYPE_VLAN, expect_layer_type); + } + } + break; + + case ETH_P_IP: + if(__ADDR_TYPE_IP_PAIR_V4 == expect_layer_type){ + break; + }else{ + skip_len = ipv4_jump_to_layer(next_layer_data, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type); + } + break; + + case ETH_P_IPV6: + if(__ADDR_TYPE_IP_PAIR_V6 == expect_layer_type){ + break; + }else{ + skip_len = ipv6_jump_to_layer(next_layer_data, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type); + } + break; + + case ETH_P_PPP_SES: + if(ADDR_TYPE_PPPOE_SES == expect_layer_type){ + break; + }else{ + skip_len = ppp_jump_to_layer(next_layer_data, ADDR_TYPE_PPPOE_SES, expect_layer_type); + } + break; + + case 0x88A8: /* MAC_IN_MAC */ + skip_len = eth_jump_to_layer(next_layer_data, ADDR_TYPE_MAC, expect_layer_type); + break; + + case 0x8847: /* MPLS, ETH_P_MPLS_UC */ + skip_len = mpls_jump_to_layer(next_layer_data, ADDR_TYPE_MPLS, expect_layer_type); + break; + + default: + skip_len = -1; + break; + } + + return skip_len; +} + +static int vlan8021q_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type) +{ + int skip_len = 0; + const struct mesa_vlan_hdr *vlan_hdr = (const struct mesa_vlan_hdr *)raw_data; + const char *next_layer_data = raw_data + sizeof(struct mesa_vlan_hdr); + + if(raw_layer_type == expect_layer_type){ + return 0; + } + + switch(ntohs(vlan_hdr->type)){ + case ETH_P_ARP: + if(ADDR_TYPE_ARP == expect_layer_type){ + break; + }else{ + skip_len = arp_jump_to_layer(next_layer_data, ADDR_TYPE_ARP, expect_layer_type); + } + break; + + case ETH_P_IP: + if(__ADDR_TYPE_IP_PAIR_V4 == expect_layer_type){ + break; + }else{ + skip_len = ipv4_jump_to_layer(next_layer_data, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type); + } + break; + + case ETH_P_IPV6: + if(__ADDR_TYPE_IP_PAIR_V6 == expect_layer_type){ + break; + }else{ + skip_len = ipv6_jump_to_layer(next_layer_data, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type); + } + break; + + case ETH_P_PPP_SES: + if(ADDR_TYPE_PPPOE_SES == expect_layer_type){ + break; + }else{ + skip_len = ppp_jump_to_layer(next_layer_data, ADDR_TYPE_PPPOE_SES, expect_layer_type); + } + break; + + case ETH_P_PPP_DISC: /* pppoe发现阶段 */ + skip_len = -1; + break; + + case 0x8200: /* XinJing捕包发现此类型, 未知什么包 */ + skip_len = -1; + break; + + default: + printf("TODO: jmp unsupport type in vlan8021q, 0x%x!\n", ntohs(vlan_hdr->type)); + skip_len = -1; + } + + if(skip_len < 0){ + return -1; + } + + return skip_len + sizeof(struct mesa_vlan_hdr); +} + +static int eth_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type) +{ + struct ethhdr *p_eth_hdr = (struct ethhdr *)raw_data; + unsigned short eth_type = ntohs(p_eth_hdr->h_proto); + //int skip_len = -1; + const char *next_layer_data = raw_data + sizeof(struct ethhdr); + int layer_skip_len; + + if(raw_layer_type == expect_layer_type){ + return 0; + } + + layer_skip_len = __common_eth_type_dispatch(eth_type, next_layer_data, raw_layer_type, expect_layer_type); + if(layer_skip_len < 0){ + return -1; + } + + return layer_skip_len + sizeof(struct ethhdr); +} + + +static int mac_in_mac_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type) +{ + struct ethhdr *inner_eth_hdr = (struct ethhdr *)(raw_data + sizeof(struct ethhdr )); + unsigned short inner_eth_type = ntohs(inner_eth_hdr->h_proto); + //int skip_len = -1; + const char *next_layer_data = raw_data + sizeof(struct ethhdr); + int layer_skip_len; + + if(raw_layer_type == expect_layer_type){ + return 0; + } + + layer_skip_len = __common_eth_type_dispatch(inner_eth_type, next_layer_data, raw_layer_type, expect_layer_type); + if(layer_skip_len < 0){ + return -1; + } + + return layer_skip_len + sizeof(struct ethhdr) * 2; +} + +/* + return value: + Non-NULL: the pointer to expect layer; + NULL: not found expect layer. +*/ +const void *MESA_net_jump_to_layer(const void *raw_data, int raw_layer_type, int expect_layer_type) +{ + int ret; + + if(raw_layer_type <= __ADDR_TYPE_INIT || raw_layer_type >= __ADDR_TYPE_MAX){ + return NULL; + } + + if(expect_layer_type <= __ADDR_TYPE_INIT || expect_layer_type >= __ADDR_TYPE_MAX){ + return NULL; + } + + if(ADDR_TYPE_IPV4 == expect_layer_type){ + /* 转成纯IPv4地址类型 */ + expect_layer_type = __ADDR_TYPE_IP_PAIR_V4; + } + + if(ADDR_TYPE_IPV6 == expect_layer_type){ + /* 转成纯IPv6地址类型 */ + expect_layer_type = __ADDR_TYPE_IP_PAIR_V6; + } + + if(raw_layer_type == expect_layer_type){ + return raw_data; + } + + switch(raw_layer_type){ + case ADDR_TYPE_MAC: + ret = eth_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type); + break; + + case ADDR_TYPE_ARP: + ret = arp_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type); + break; + case ADDR_TYPE_VLAN: + if(treat_vlan_as_mac_in_mac_sw){ + ret = mac_in_mac_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type); + }else{ + ret = vlan8021q_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type); + } + break; + + case __ADDR_TYPE_IP_PAIR_V4: + ret = ipv4_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type); + break; + + case __ADDR_TYPE_IP_PAIR_V6: + ret = ipv6_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type); + break; + + case ADDR_TYPE_MAC_IN_MAC: + ret = mac_in_mac_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type); + break; + + case ADDR_TYPE_UDP: + ret = udp_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type); + break; + + case ADDR_TYPE_PPPOE_SES: + case ADDR_TYPE_MPLS: + case ADDR_TYPE_GRE: + default: + printf("TODO: jmp unsupport raw_layer_type:%d in MESA_net_jump_to_layer()!\n", raw_layer_type); + return NULL; + } + + if(ret < 0){ + return NULL; + } + + return ((const char *)raw_data + ret); +} + +/* + 与MESA_net_jump_to_layer()的区别: + MESA_net_jump_to_layer()从最外层开始, 找到第一个符合条件的层就退出; + MESA_net_jump_to_layer_greedy()会一直尝试找最内层协议头, 适合隧道模式. + + return value: + Non-NULL: the pointer to expect layer; + NULL: not found expect layer. +*/ +const void *MESA_net_jump_to_layer_greedy(const void *raw_data, int raw_layer_type, int expect_layer_type) +{ + const void *expect_layer; + const void *success_layer = NULL; /* 最后一次成功找到的层 */ + int new_raw_layer_type = raw_layer_type; /* 在跳转过程中, 可能会更新中间层信息 */ + const char *new_next_layer_data = (char *)raw_data; + + expect_layer = MESA_net_jump_to_layer(new_next_layer_data, new_raw_layer_type, expect_layer_type); + while(expect_layer){ + success_layer = expect_layer; + + switch(expect_layer_type){ + case __ADDR_TYPE_IP_PAIR_V4: + { + const struct mesa_ip4_hdr *ip4hdr = (const struct mesa_ip4_hdr *)expect_layer; + if(IPPROTO_UDP == ip4hdr->ip_p){ + new_next_layer_data = (char *)expect_layer + ip4hdr->ip_hl * 4; + new_raw_layer_type = ADDR_TYPE_UDP; /* IP层如果继续向下一层偏移, 只支持UDP, IPIP, GRE, L2TPv3. */ + }else{ + //TODO 2, GRE, IPIP, L2TPv3 + goto done; + } + } + break; + + case __ADDR_TYPE_IP_PAIR_V6: + { + //TODO2, + //sapp_runtime_log(20, "MESA_net_jump_to_layer_greedy() not support IPv6 layer yet\n"); + goto done; + } + break; + + default: + //sapp_runtime_log(20, "MESA_net_jump_to_layer_greedy() not support layer type:%d\n", expect_layer_type); + goto done; + } + + expect_layer = MESA_net_jump_to_layer(new_next_layer_data, new_raw_layer_type, expect_layer_type); + } + +done: + return success_layer; +} + +UINT8 net_layer_to_ipv4_protocol(int addr_type) +{ + UINT8 proto = 0; + + switch(addr_type){ + case __ADDR_TYPE_IP_PAIR_V4: + proto = IPPROTO_IPIP; + break; + + case __ADDR_TYPE_IP_PAIR_V6: + proto = IPPROTO_IPV6; + break; + + case ADDR_TYPE_TCP: + proto = IPPROTO_TCP; + break; + + case ADDR_TYPE_UDP: + proto = IPPROTO_UDP; + break; + + case ADDR_TYPE_GRE: + proto = IPPROTO_GRE; + break; + + default: + printf("unknown ip4 protocolr:%d\n", addr_type); + proto = 0xFF; + break; + } + + return proto; +} + +UINT8 net_layer_to_ipv6_protocol(int addr_type) +{ + UINT8 proto = 0; + + switch(addr_type){ + case ADDR_TYPE_TCP: + proto = 6; //NEXTHDR_TCP; + break; + + case ADDR_TYPE_UDP: + proto = 17;///NEXTHDR_UDP; + break; + + case __ADDR_TYPE_IP_PAIR_V4: + proto = 4;///NEXTHDR_IPIP; + break; + + default: + printf("unknown ip6 next-hdr:%d\n", addr_type); + return 0xFF; + break; + } + + return proto; +} + +/* + 将MESA地址类型转换为标准Ethernet类型; + + return value: + ethernet type, host order. +*/ +UINT16 net_layer_to_ethernet_protocol(int addr_type) +{ + UINT16 ether_type = 0; + + switch(addr_type){ + case __ADDR_TYPE_IP_PAIR_V4: + ether_type = ETH_P_IP; + break; + + case __ADDR_TYPE_IP_PAIR_V6: + ether_type = ETH_P_IPV6; + break; + + case ADDR_TYPE_VLAN: + ether_type = ETHERTYPE_VLAN; + break; + + case ADDR_TYPE_TCP: + case ADDR_TYPE_UDP: + //sapp_runtime_log(RLOG_LV_FATAL, "%s:%d: Ethernet can't carry addr type:%d directly!\n", __FILE__, __LINE__,addr_type); + //assert(0); + ether_type = -1; + break; + + case ADDR_TYPE_PPPOE_SES: + ether_type = ETH_P_PPP_SES; + break; + + case ADDR_TYPE_MPLS: + ether_type = ETH_P_MPLS_UC; + break; + + case ADDR_TYPE_ARP: + ether_type = ETH_P_ARP; + break; + + default: + /* to do, unknown type */ + ///sapp_runtime_log(RLOG_LV_FATAL, "%s:%d: Ethernet addr type:%d!\n", __FILE__, __LINE__, addr_type); + ether_type = -1; + break; + } + + return ether_type; +} + + +/* 删除末尾的换行符"\r\n" */ +void del_last_rn(char *data, int max_len) +{ + int i; + for(i = 0; i < max_len; i++){ + if(('\r' == data[i]) || ('\n' == data[i])){ + data[i] = '\0'; + return; + } + } + + return; +} + +/* + 返回值: + ethernet长度, 包括eth头部. +*/ +int get_pkt_len_from_eth_hdr(const struct mesa_ethernet_hdr *ehdr) +{ + int raw_pkt_len = -1; + + switch(ntohs(ehdr->ether_type)){ + case ETHERTYPE_IP: + { + struct mesa_ip4_hdr *ip4hdr = (struct mesa_ip4_hdr *)((char *)ehdr + sizeof(struct mesa_ethernet_hdr)); + raw_pkt_len = ntohs(ip4hdr->ip_len) + sizeof(struct mesa_ethernet_hdr); + } + break; + + case ETHERTYPE_IPv6: + { + struct mesa_ip6_hdr *ip6hdr = (struct mesa_ip6_hdr *)((char *)ehdr + sizeof(struct mesa_ethernet_hdr)); + raw_pkt_len = ntohs(ip6hdr->ip6_payload_len) + sizeof(struct mesa_ip6_hdr) + sizeof(struct mesa_ethernet_hdr); + } + break; + + default: + break; + } + + return raw_pkt_len; +} + + +#ifdef __cplusplus +} +#endif + diff --git a/stream_base.h b/stream_base.h new file mode 100644 index 0000000..2311cee --- /dev/null +++ b/stream_base.h @@ -0,0 +1,520 @@ +#ifndef _APP_STREAM_BASE_H_ +#define _APP_STREAM_BASE_H_ + +#define STREAM_BASE_H_VERSION (20170616) + +#include +#include +#include + +#ifndef UINT8 +typedef unsigned char UINT8; +#endif +#ifndef UCHAR +typedef unsigned char UCHAR; +#endif +#ifndef UINT16 +typedef unsigned short UINT16; +#endif + +#ifndef UINT32 +typedef unsigned int UINT32; +#endif +#ifndef UINT64 +typedef unsigned long long UINT64; +#endif + +/* CHN : 流的方向定义 */ +/* ENG : stream direction definition*/ +#define DIR_C2S 0x01 +#define DIR_S2C 0x02 +#define DIR_DOUBLE 0x03 + +/* CHN : 网络底层传输方向定义,串联模式有意义 */ +/* ENG : network topology route direction, is valid in serial mode */ +#define DIR_ROUTE_UP 0x00 +#define DIR_ROUTE_DOWN 0x01 + +/* CHN : 单包的类型定义 */ +/* ENG : single packet type definition */ +#define PKT_TYPE_NORMAL (0x0) /* normal, common */ +#define PKT_TYPE_IPREBUILD (1<<0) /* ip frag reassembled packet; ip碎片重组报文 */ +#define PKT_TYPE_TCPUNORDER (1<<1) /* TCP out of order packet; TCP乱序报文 */ +#define PKT_TYPE_TCPREORDER (1<<2) /* TCP sequential packet; TCP乱序排序好的数据包 */ +#define PKT_TYPE_TCPRETRANS (1<<3) /* TCP retransmit packet; TCP重传报文 */ +#define PKT_TYPE_IP_FRAG (1<<4) /* IP frag packet; IP分片包 */ +#define PKT_TYPE_IP_FRAG_LAST (1<<5) /* last IP frag packet; 同属于一个原始完整IP包的最后一个IP分片包 */ + +/* CHN : 地址类型定义, 可通过函数 addr_type_to_string() 转成字符串形式. */ +/* ENG : address type, transform to string mode by call addr_type_to_string(). */ +enum addr_type_t{ + __ADDR_TYPE_INIT = 0, + ADDR_TYPE_IPV4, /* 1, struct stream_tuple4_v4 */ + ADDR_TYPE_IPV6, /* 2, struct stream_tuple4_v6 */ + ADDR_TYPE_VLAN, /* 3 */ + ADDR_TYPE_MAC, /* 4 */ + ADDR_TYPE_ARP = 5, /* 5 */ + ADDR_TYPE_GRE, /* 6 */ + ADDR_TYPE_MPLS, /* 7 */ + ADDR_TYPE_PPPOE_SES, /* 8 */ + ADDR_TYPE_TCP, /* 9 */ + ADDR_TYPE_UDP = 10, /* 10 */ + ADDR_TYPE_L2TP, /* 11 */ + __ADDR_TYPE_IP_PAIR_V4, /* 12, ipv4 layer in tunnel mode */ + __ADDR_TYPE_IP_PAIR_V6, /* 13, ipv6 layer in tunnel mode */ + ADDR_TYPE_PPP, /* 14 */ + ADDR_TYPE_PPTP, /* 15 */ + ADDR_TYPE_MAC_IN_MAC, /* 16 */ + ADDR_TYPE_GPRS_TUNNEL, /* 17 */ + __ADDR_TYPE_MAX, /* 18 */ +}; + +#define TCP_TAKEOVER_STATE_FLAG_OFF 0 +#define TCP_TAKEOVER_STATE_FLAG_ON 1 + + +/* CHN : 应用层看到的链接状态定义 */ +/* ENG : stream state for protocol or business plug*/ +#define OP_STATE_PENDING 0 +#define OP_STATE_REMOVE_ME 1 +#define OP_STATE_CLOSE 2 +#define OP_STATE_DATA 3 + +/* CHN : 应用层返回结果定义 */ +/* ENG : return value of plug */ +#define APP_STATE_GIVEME 0x00 +#define APP_STATE_DROPME 0x01 +#define APP_STATE_FAWPKT 0x00 +#define APP_STATE_DROPPKT 0x10 + +/* CHN : 流的类型定义 */ +/* ENG : stream type */ +enum stream_type_t{ + STREAM_TYPE_NON = 0, /* No stream concept indeed, such as vlan, IP, etc.; 无流的概念, 如VLAN, IP层等 */ + STREAM_TYPE_TCP, + STREAM_TYPE_UDP, /* there is no stream of UDP in RFC, but in MESA platform, we build a UDP stream with same tuple4 packet */ + STREAM_TYPE_VLAN, + STREAM_TYPE_SOCKS4, + STREAM_TYPE_SOCKS5, + STREAM_TYPE_HTTP_PROXY, + STREAM_TYPE_PPPOE, + STREAM_TYPE_L2TP, + STREAM_TYPE_OPENVPN, + STREAM_TYPE_PPTP, + STREAM_TYPE_ISAKMP, +}; + +/* + CHN: 流的底层承载隧道类型, + 不同于stream_type_t, 比如当前流为STREAM_TYPE_TCP, 但底层隧道类型可能是STREAM_TUNNLE_PPTP. + 因为隧道可能是多种不同类型嵌套组合, 只记录最底层(离MAC层最近的)隧道类型. +*/ +enum stream_carry_tunnel_t{ + STREAM_TUNNLE_NON = 0, /* default is 0, not tunnel; 默认为0, 非隧道; */ + STREAM_TUNNLE_6OVER4 = 1 << 0, + STREAM_TUNNLE_4OVER6 = 1 << 1, + STREAM_TUNNLE_GRE = 1 << 2, + STREAM_TUNNLE_IP_IN_IP = 1 << 3, + STREAM_TUNNLE_PPTP = 1 << 4, + STREAM_TUNNLE_L2TP = 1 << 5, + STREAM_TUNNLE_TEREDO = 1 << 6, + STREAM_TUNNEL_GPRS_TUNNEL = 1 << 7, +}; + +typedef struct raw_ipfrag_list{ + void *frag_packet; + int pkt_len; + int type; /* IPv4 or IPv6 */ + struct raw_ipfrag_list *next; +}raw_ipfrag_list_t; + + +#ifndef STRUCT_TUPLE4_DEFINED +#define STRUCT_TUPLE4_DEFINED (1) +/* compat for start, papp; 兼容start, papp */ +struct tuple4 { + u_int saddr; + u_int daddr; + u_short source; + u_short dest; +}; +#endif + +struct tuple6 +{ + UCHAR saddr[16] ; + UCHAR daddr[16] ; + UINT16 source; + UINT16 dest; +}; + +/* network-order */ +struct stream_tuple4_v4{ + UINT32 saddr; /* network order */ + UINT32 daddr; /* network order */ + UINT16 source; /* network order */ + UINT16 dest; /* network order */ +}; + + +#ifndef IPV6_ADDR_LEN +#define IPV6_ADDR_LEN (sizeof(struct in6_addr)) +#endif + +struct stream_tuple4_v6 +{ + UCHAR saddr[IPV6_ADDR_LEN] ; + UCHAR daddr[IPV6_ADDR_LEN] ; + UINT16 source; /* network order */ + UINT16 dest; /* network order */ +}; + + +#define GRE_TAG_LEN (4) +struct layer_addr_gre +{ + UINT16 call_id; /* network order */ +}; + + +#define VLAN_ID_MASK (0x0FFF) +#define VLAN_TAG_LEN (4) +struct layer_addr_vlan +{ + UINT16 vlan_id; /* network order */ +}; + +#define VLAN_ID_LEN 4 +struct tuplevlan +{ + UCHAR vlan_id[VLAN_ID_LEN]; +}; + +struct layer_addr_pppoe_session +{ +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ver:4; + unsigned int type:4; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int type:4; + unsigned int ver:4; +#endif + unsigned char code; + unsigned short session_id; +}; + +#ifndef MAC_ADDR_LEN +#define MAC_ADDR_LEN (6) +#endif + +struct layer_addr_mac +{ + UCHAR dst_mac[MAC_ADDR_LEN]; /* network order */ + UCHAR src_mac[MAC_ADDR_LEN]; /* network order */ +}; + +struct layer_addr_ipv4 +{ + UINT32 saddr; /* network order */ + UINT32 daddr; /* network order */ + /* 2014-04-21 lijia add, + 为了节约内存空间、和处理效率, 不强制按协议层次处理, + IP层和TCP层做为一个层, + 对于隧道外层IP, 端口信息为0; + */ + UINT16 source; /* network order */ + UINT16 dest; /* network order */ +}; + +struct layer_addr_ipv6 +{ + UCHAR saddr[IPV6_ADDR_LEN] ; /* network order */ + UCHAR daddr[IPV6_ADDR_LEN] ; /* network order */ + /* 2014-04-21 lijia add, + 为了节约内存空间、和处理效率, 不强制按协议层次处理, + IP层和TCP层做为一个层, + 对于隧道外层IP, 端口信息为0; + */ + UINT16 source;/* network order */ + UINT16 dest;/* network order */ +}; + +struct layer_addr_tcp +{ + UINT16 source; /* network order */ + UINT16 dest; /* network order */ +}; + +struct layer_addr_udp +{ + UINT16 source; /* network order */ + UINT16 dest; /* network order */ +}; + + +struct layer_addr_l2tp_v2_t{ + UINT16 tunnelid_C2S; /* network order, 以传输层创建流的方向为准 */ + UINT16 tunnelid_S2C; /* network order, 以传输层创建流的方向为准 */ + UINT16 sessionid_C2S; /* network order, 以传输层创建流的方向为准 */ + UINT16 sessionid_S2C; /* network order, 以传输层创建流的方向为准 */ +}; + +struct layer_addr_l2tp_v3_t{ + UINT32 sessionlid; /* network order */ +}; + +struct layer_addr_l2tp +{ + UCHAR version; /* v2 or v3 */ + union + { + struct layer_addr_l2tp_v2_t l2tp_addr_v2; + struct layer_addr_l2tp_v3_t l2tp_addr_v3; + }l2tpun; +}; + +#define MAX_MPLS_ADDR_LAYER 4 +struct layer_addr_mpls +{ + unsigned int mpls_pkt[MAX_MPLS_ADDR_LAYER]; + char mpls_layer_num; +}; + +struct layer_addr_pptp +{ + UINT16 C2S_call_id; /* C2S以传输层协议方向为准, TCP SYN为C2S, UDP源端口大的为C2S, callid, network order */ + UINT16 S2C_call_id; /* S2Ck以传输层协议方向为准, TCP SYN/ACK为S2C, UDP目的端口大的为S2C, callid, network order */ +}; + +struct layer_addr_gtp +{ + unsigned long long source; + unsigned int src_seq; + unsigned long long dest; + unsigned int dest_seq; +}__attribute__ ((aligned (1))); + +#define MAC_IN_MAC_HDR_LEN (sizeof(struct mesa_ethernet_hdr) + sizeof(struct mesa_ethernet_hdr)) +struct layer_addr_mac_in_mac +{ + UCHAR outer_dst_mac[MAC_ADDR_LEN]; /* 最外层mac地址, network order */ + UCHAR outer_src_mac[MAC_ADDR_LEN]; /* 最外层mac地址, network order */ + UCHAR inner_dst_mac[MAC_ADDR_LEN]; /* 内层mac地址, network order */ + UCHAR inner_src_mac[MAC_ADDR_LEN]; /* 内层mac地址, network order */ +}; + +struct layer_addr +{ + UCHAR addrtype; /* definition in enum addr_type_t */ + UCHAR addrlen; + UCHAR pkttype; /* packet special features, definition in MACRO PKT_TYPE_xxx */ + UCHAR pktipfragtype; /* ip frag packetfeatures, definition in MACRO PKT_TYPE_xxx */ + + UCHAR __pad[4]; /* pad for alignment */ + union + { + struct stream_tuple4_v4 *tuple4_v4; + struct stream_tuple4_v6 *tuple4_v6; + struct layer_addr_ipv4 *ipv4; + struct layer_addr_ipv6 *ipv6; + struct layer_addr_vlan *vlan; + struct layer_addr_mac *mac; + struct layer_addr_gre *gre; + struct layer_addr_tcp *tcp; + struct layer_addr_udp *udp; + struct layer_addr_pppoe_session *pppoe_ses; + struct layer_addr_l2tp *l2tp; + struct layer_addr_pptp *pptp; + struct layer_addr_mac_in_mac *mimac; + struct layer_addr_gtp *gtp; + void *paddr; + }; + +}; + +/* CHN : 保留此结构用于和papp兼容, 用作指针时, 可与struct layer_addr强转 */ +/* ENG : compat for papp, can be transform to struct layer_addr pointer */ +struct ipaddr +{ + UCHAR addrtype; /* definition in enum addr_type_t */ + UCHAR addrlen; + UCHAR pkttype; /* packet special features, definition in MACRO PKT_TYPE_xxx */ + UCHAR pktipfragtype; /* ip frag packetfeatures, definition in MACRO PKT_TYPE_xxx */ + UCHAR __pad[4]; /* pad for alignment */ + union + { + struct stream_tuple4_v4 *v4; + struct stream_tuple4_v6 *v6; + void *paddr; + }; + +}; + +struct tcpdetail +{ + void *pdata; + UINT32 datalen; + UINT32 lostlen; /* lost data len, not accumulated, current procedure */ + UINT32 serverpktnum; /* C2S, this value indicate TCP-ALL packet, include syn, ack, rst, if want get tcp data status, use stream_project.h : struct tcp_flow_stat */ + UINT32 clientpktnum; /* S2C, this value indicate TCP-ALL packet, include syn, ack, rst, if want get tcp data status, use stream_project.h : struct tcp_flow_stat */ + UINT32 serverbytes; /* C2S, this value indicate TCP-ALL packet, include syn, ack, rst, if want get tcp data status, use stream_project.h : struct tcp_flow_stat */ + UINT32 clientbytes; /* S2C, this value indicate TCP-ALL packet, include syn, ack, rst, if want get tcp data status, use stream_project.h : struct tcp_flow_stat */ + UINT64 createtime; + UINT64 lastmtime; +}; + +struct udpdetail +{ + void *pdata; + UINT32 datalen; + UINT32 pad; + UINT32 serverpktnum; /* C2S, you should better use stream_project.h : struct udp_flow_stat */ + UINT32 clientpktnum; /* S2C, you should better use stream_project.h : struct udp_flow_stat */ + UINT32 serverbytes; /* C2S, you should better use stream_project.h : struct udp_flow_stat */ + UINT32 clientbytes; /* S2C, you should better use stream_project.h : struct udp_flow_stat */ + UINT64 createtime; + UINT64 lastmtime; +}; + +struct streaminfo +{ + struct layer_addr addr; + struct streaminfo *pfather; /* this stream's carry layer stream; 上层流结构体 */ + UCHAR type; /* stream type, definition in enum stream_type_t */ + UCHAR threadnum; + UCHAR dir; /* valid in all stream life, current stream direction state, 0x01:c-->s; 0x02:s-->c; 0x03 c<-->s; */ + UCHAR curdir; /* valid in current procedure, current packet direction, 0x01:c-->s; 0x02:s-->c */ + UCHAR opstate; /* stream state, definition in MACRO OP_STATE_xxx */ + UCHAR pktstate; /* for TCPALL plug, stream state, definition in MACRO OP_STATE_xxx */ + UCHAR routedir; /* network topology route direction, is valid in serial mode */ + UCHAR stream_state; /* stream management state, for example, in TCP stream, maybe SYN, DATA, NOUSE */ + UINT32 hash_index; /* stream hash index, maybe reduplicate with other stream when hash algorithm collide */ + UINT32 stream_index; /* stream global index per thread */ + union + { + struct tcpdetail *ptcpdetail; + struct udpdetail *pudpdetail; + void *pdetail; + }; + }; + + + +#ifdef __cplusplus +extern "C" { +#endif + +/* CHN : 内存管理相关函数, 基于平台的插件必须使用此类函数申请或释放内存 */ +/* ENG : memory management function, plugs must call these functions instead of malloc, free in */ +void *dictator_malloc(int thread_seq,size_t size); +void dictator_free(int thread_seq,void *pbuf); +void *dictator_realloc(int thread_seq, void* pbuf, size_t size); + +/* CHN : 获取当前系统运行的并发处理线程总数 */ +/* ENG : get current total thread of platfomr */ +int get_thread_count(void); + +/* CHN : 将地enum addr_type_t址类型转换成可打印的字符串形式 */ +/* ENG : transform binary addr_type_t to string mode */ +const char *addr_type_to_string(enum addr_type_t type); + +/* + ENG : transform tuple4 to string mode, must used in packet process thread context; + CHN : 将layer_addr地址转换成字符串形式, 必须用在包处理线程. +*/ +const char *printaddr (const struct layer_addr *paddrinfo, int threadindex); + +/* + ENG : a reentrant version of printaddr, thread safe; + CHN : printaddr的可重入版本, 是线程安全的. +*/ +const char *printaddr_r(const struct layer_addr *paddrinfo, char *out_buf, int out_buf_len); + + +/* + ENG : transform layer address to string mode, must used in packet process thread context, + the return value is read-only, user can't free it; + CHN : 将layer_addr地址转换成字符串形式, 必须用在包处理线程, 返回的指针为只读, 使用者不必free. +*/ +const char *layer_addr_ntop(const struct streaminfo *pstream); + +/* + ENG : a reentrant version of layer_addr_ntop, thread safe, return a pointer to the destination string 'out_buf'; + CHN : layer_addr_ntop_r的可重入版本, 是线程安全的, 返回的指针执向使用者提供的out_buf, 便于代码组织. +*/ +char *layer_addr_ntop_r(const struct streaminfo *pstream, char *out_buf, int out_buf_len); + +/* + ENG : transform layer type to abbr string mode, is reentrant, the return value is read-only, user can't free it;. + CHN : 将layer_addr地址类型转换成缩写字符串形式, 可重入线程安全, 返回的指针为只读, 使用者不必free.. +*/ +const char *layer_addr_prefix_ntop(const struct streaminfo *pstream); + + +/* + ENG : duplicate a same layer_addr struct, memory obtained with malloc(3); + CHN : 复制一个完全相同的layer_addr结构体, 内存通过malloc(3)获取. +*/ +struct layer_addr * layer_addr_dup(const struct layer_addr *paddrinfo); + +/* + ENG: used to free all memory of paddrinfo; + CHN: 用于释放paddrinfo内存. +*/ +void layer_addr_free(struct layer_addr *paddrinfo); + + +/* + ENG : duplicate a same streaminfo list, memory obtained with malloc(3); + CHN : 复制一个完全相同的streaminfo结构体及父流结构, 内存通过malloc(3)获取. +*/ +struct streaminfo *streaminfo_dup(const struct streaminfo *stream); + +/* + ENG: used to free all memory of streaminfo; + CHN: 用于释放结构体及父流结构的内存. +*/ +void streaminfo_free(struct streaminfo *stream); + + +/* + addr list transform function, like inet_ntop(), inet_pton(), + use '<' as delimitation between layer, + if direction is double, for ip, port, use '-' as delimitation between source and destination, + + for example: + "T4T:6005-16730:转换后的结果实际占用内存长度, stream_addr_list_ntop()包含了字符串末尾的'\0'; + -1:dst缓存空间长度不足; + -2:格式错误; + -3:其他错误; +*/ +int stream_addr_list_ntop(const struct streaminfo *pstream, char *dst, int size); +int stream_addr_list_pton(const char *addr_list_str, void *dst, int size, int thread_index); + +/* + TCP,UDP流模式下, 获取当前IP包的原始分片包. +*/ +const raw_ipfrag_list_t *get_raw_frag_list(const struct streaminfo *stream); + +/* + IP插件模式下, 获取当前IP包的原始分片包. +*/ +const raw_ipfrag_list_t *ip_plug_get_raw_ipfrag_list(int thread_num, enum addr_type_t addr_type); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/tcp.h b/tcp.h index 02df629..a76b9e5 100644 --- a/tcp.h +++ b/tcp.h @@ -32,6 +32,8 @@ * * @(#)tcp.h 8.1 (Berkeley) 6/10/93 */ +#ifndef _tcpdump_tcp_h +#define _tcpdump_tcp_h 1 typedef uint32_t tcp_seq; /* @@ -157,3 +159,6 @@ struct tcphdr { #ifndef REDIS_PORT #define REDIS_PORT 6379 #endif + +#endif + diff --git a/tcpdump.c b/tcpdump.c index f613a67..246805a 100644 --- a/tcpdump.c +++ b/tcpdump.c @@ -44,13 +44,15 @@ #define MESA_DUMP (1) #if MESA_DUMP #include "mesa_pkt_dump.h" -const int tcpdump_mesa_version_VERSION_20180119 = 20180119; +const int tcpdump_mesa_version_VERSION_20181114 = 20181114; int tcpdump_data_offset = 0; /* 用于跳过某些底层数据, 如vxlan, 可以直接获取或设置过滤条件看vxlan的内层数据包内容 */ unsigned char tcpdump_thread_index_array[64]; /* 开启捕包线程id数组, 靠长度决定id数量, 每个占1字节, 命令行输入支持逗号分隔 */ int tcpdump_thread_index_array_num = 0; const char *tcpdump_thread_index_str; int tcpdump_perceptive_flag = 0; unsigned int perceptive_pkt_seq[256]; /* 最大支持256个线程 */ +static int greedy_seek_flag = 0; /* 偏移到最内层IP, 便于隧道模式下查找BUG */ +static int dump_to_file_flag = 0; /* 是否有-w 参数 */ #endif #ifndef lint @@ -485,8 +487,8 @@ show_devices_and_exit (void) #define Q_FLAG #endif -#if MESA_DUMP /* lijia add, 新增参数k, o, P */ -#define SHORTOPTS "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hHi:" I_FLAG j_FLAG J_FLAG "k:KlLm:M:nNo:OP:pq" Q_FLAG "r:s:StT:u" U_FLAG "vV:w:W:xXy:Yz:Z:#" +#if MESA_DUMP /* lijia add, 新增参数g, k, o, P */ +#define SHORTOPTS "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:gG:hHi:" I_FLAG j_FLAG J_FLAG "k:KlLm:M:nNo:OP:pq" Q_FLAG "r:s:StT:u" U_FLAG "vV:w:W:xXy:Yz:Z:#" #else #define SHORTOPTS "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hHi:" I_FLAG j_FLAG J_FLAG "KlLm:M:nNOpq" Q_FLAG "r:s:StT:u" U_FLAG "vV:w:W:xXy:Yz:Z:#" #endif @@ -786,7 +788,85 @@ set_dumper_capsicum_rights(pcap_dumper_t *p) #endif #if MESA_DUMP +#include "mesa_net.h" +#include "stream_base.h" +static int MESA_dump_seek_to_inner(char *pkt_buf, int pktlen) +{ + struct mesa_ethernet_hdr *ehdr = (struct mesa_ethernet_hdr *)pkt_buf; + char *first_ip_layer = NULL; + struct mesa_ip4_hdr *ip4hdr_greedy; + struct mesa_ip6_hdr *ip6hdr_greedy; + int bpf_match_pkt_len = -1; + int bpf_match_ipv4 = 0, bpf_match_ipv6 = 0; + if(ETHERTYPE_IP == ntohs(ehdr->ether_type)){ + first_ip_layer = pkt_buf + sizeof(struct mesa_ethernet_hdr); + }else if(ETHERTYPE_IPv6 == ntohs(ehdr->ether_type)){ + first_ip_layer = pkt_buf + sizeof(struct mesa_ethernet_hdr); + }else{ + first_ip_layer = NULL; + } + + ip4hdr_greedy = (struct mesa_ip4_hdr *)MESA_net_jump_to_layer_greedy(pkt_buf, ADDR_TYPE_MAC, __ADDR_TYPE_IP_PAIR_V4); + if(ip4hdr_greedy){ + if((char *)ip4hdr_greedy == first_ip_layer){ + bpf_match_pkt_len = pktlen; /* 最内层和第一层IP一样, 说明是标准ethernet->IPv4包, 无需memmove操作 */ + }else{ + memmove(pkt_buf + sizeof(struct mesa_ethernet_hdr), + ip4hdr_greedy, + pktlen - ((char *)ip4hdr_greedy - pkt_buf)); + bpf_match_pkt_len = pktlen - ((char *)ip4hdr_greedy - pkt_buf) + sizeof(struct mesa_ethernet_hdr); + ehdr->ether_type = htons(ETHERTYPE_IP); /* 第一层可能不是IPV4, 比如MPLS, VLAN等, 需要改成IP, 以便bpf过滤器能正确执行 */ + } + + if(bpf_match_pkt_len <= 0){ + return -1; + } + + /* 如果有正确的过滤条件, 不设采样率, 保证捕包尽量全, 符合调用者意图; + 如果没有过滤条件, 即全捕包模式, 为了尽量不影响包处理线程, 根据采样率只捕一部分包. + */ + + bpf_match_ipv4 = 1; + }else{ + bpf_match_ipv4 = 0; + } + + ip6hdr_greedy = (struct mesa_ip6_hdr *)MESA_net_jump_to_layer_greedy(pkt_buf, ADDR_TYPE_MAC, __ADDR_TYPE_IP_PAIR_V6); + if(ip6hdr_greedy){ + if((char *)ip6hdr_greedy == first_ip_layer){ + bpf_match_pkt_len = pktlen; /* 最内层和第一层IP一样, 说明是标准ethernet->IPv6包, 无需memmove操作 */ + }else{ + memmove(pkt_buf + sizeof(struct mesa_ethernet_hdr), + ip6hdr_greedy, + pktlen - ((char *)ip6hdr_greedy - pkt_buf)); + bpf_match_pkt_len = pktlen - ((char *)ip4hdr_greedy - pkt_buf) + sizeof(struct mesa_ethernet_hdr); + ehdr->ether_type = htons(ETHERTYPE_IPv6); /* 第一层可能不是IPV6, 比如MPLS, VLAN等,需要改成IP,以便bpf过滤器能正确执行 */ + } + + if(bpf_match_pkt_len <= 0){ + ///sapp_runtime_log(20, "cycle_pkt_dump_seek_to_inner_ip() length error!\n"); + return -1; + } + + + /* 如果有正确的过滤条件, 不设采样率, 保证捕包尽量全, 符合调用者意图; + 如果没有过滤条件, 即全捕包模式, 为了尽量不影响包处理线程, 根据采样率只捕一部分包. + */ + bpf_match_ipv6 = 1; + }else{ + bpf_match_ipv6 = 0; + } + + if(bpf_match_ipv4 || bpf_match_ipv6){ + return bpf_match_pkt_len; /* 任意头部命中即可输出 */ + } + + return -1; +} + + +/* 可支持多个线程, 用逗号分隔"1,3,5,7" */ static int MESA_dump_thread_index_convert(const char *raw_index_str) { char *index_str = strdup(raw_index_str); @@ -878,6 +958,24 @@ static int pkt_dump_recv_ack(int connfd) return 0; } +#include +static void *detect_sapp_thread(void *arg) +{ + int tcp_cmd_fd = (int)arg; + int ret; + char nouse_buf[1500]; + + while(1){ + ret = read(tcp_cmd_fd, nouse_buf, 1500); + if(0 == ret){ + printf("\033[33m[INFO]sapp is not running, tcpdump_mesa exit!\033[0m\n"); + exit(1); + } + } + + return NULL; +} + static int MESA_dump_start(unsigned short udp_rcv_port, unsigned short sapp_cmd_port, char *filter) { int tcp_cmd_fd = -1; @@ -887,6 +985,7 @@ static int MESA_dump_start(unsigned short udp_rcv_port, unsigned short sapp_cmd_ struct pkt_dump_handshake pkt_hdr; unsigned int opt_num = 1; /* 本端接收端口为必选项 */ struct pkt_dump_opt opt; + pthread_t pid; tcp_cmd_fd = socket(AF_INET, SOCK_STREAM, 0); @@ -923,7 +1022,7 @@ static int MESA_dump_start(unsigned short udp_rcv_port, unsigned short sapp_cmd_ /************** pkt handshake *************/ pkt_hdr.magic = htonl(PKT_DUMP_HDR_MAGIC); - pkt_hdr.version = htonl(tcpdump_mesa_version_VERSION_20180119); + pkt_hdr.version = htonl(tcpdump_mesa_version_VERSION_20181114); pkt_hdr.opt_num = htonl(opt_num); ret = write(tcp_cmd_fd, &pkt_hdr, sizeof(pkt_hdr)); if(ret < 0){ @@ -1012,6 +1111,8 @@ static int MESA_dump_start(unsigned short udp_rcv_port, unsigned short sapp_cmd_ exit(1); } + pthread_create(&pid, NULL, detect_sapp_thread, (void *)tcp_cmd_fd); + return tcp_cmd_fd; } @@ -1066,7 +1167,7 @@ static void MESA_dump(pcap_handler callback, u_char *pcap_userdata, char *filter int tot_pkt, unsigned short sapp_cmd_port ) { unsigned short udp_default_port = 12345; - int opt, pkt_len; + int opt, pkt_len, inner_pkt_len; unsigned char pkt_buf[65536]; struct pcap_pkthdr phony_pcap_hdr; int udp_rcv_fd = -1; @@ -1119,10 +1220,24 @@ static void MESA_dump(pcap_handler callback, u_char *pcap_userdata, char *filter } perceptive_pkt_seq[pperceptive->thread_id] = cur_pkt_seq; } - phony_pcap_hdr.caplen = pkt_len; - phony_pcap_hdr.len = pkt_len; + + /* 如果有-g参数, 且写了-w, 即需要保存原始包到文件, 则不进行seek操作, + 只是在没有-w 参数时, 让tcpdump能打印出包的信息, 才进行seek操作. + */ + if((greedy_seek_flag != 0) && (dump_to_file_flag == 0)){ + inner_pkt_len = MESA_dump_seek_to_inner(pkt_buf, pkt_len); + if(inner_pkt_len < 0){ + continue; + } + phony_pcap_hdr.caplen = inner_pkt_len; + phony_pcap_hdr.len = inner_pkt_len; + }else{ + phony_pcap_hdr.caplen = pkt_len; + phony_pcap_hdr.len = pkt_len; + } gettimeofday(&phony_pcap_hdr.ts, NULL); - callback(pcap_userdata, &phony_pcap_hdr, pkt_buf); /* 刷屏模式调用print_packet(); 捕包模式调用: dump_packet() */ + + callback(pcap_userdata, &phony_pcap_hdr, pkt_buf); /* NOTE: 刷屏模式调用print_packet(); 捕包模式调用: dump_packet() */ actual_rcv_pkt_num++; } } @@ -1302,6 +1417,13 @@ main(int argc, char **argv) case 'F': infile = optarg; break; + +#if MESA_DUMP + case 'g': + greedy_seek_flag = 1; + break; +#endif + case 'G': Gflag = atoi(optarg); @@ -1385,6 +1507,21 @@ main(int argc, char **argv) break; #endif +#if MESA_DUMP + case 'k': + tcpdump_thread_index_str = optarg; + if(MESA_dump_thread_index_convert(tcpdump_thread_index_str) < 0){ + printf("thread index invalid: %s\n", optarg); + exit(1); + } + break; +#endif + + case 'K': + ++ndo->ndo_Kflag; + break; + + case 'l': #ifdef _WIN32 /* @@ -1409,20 +1546,6 @@ main(int argc, char **argv) case 'L': Lflag++; break; - -#if MESA_DUMP - case 'k': - tcpdump_thread_index_str = optarg; - if(MESA_dump_thread_index_convert(tcpdump_thread_index_str) < 0){ - printf("thread index invalid: %s\n", optarg); - exit(1); - } - break; -#endif - - case 'K': - ++ndo->ndo_Kflag; - break; case 'm': #ifdef USE_LIBSMI @@ -1503,7 +1626,12 @@ main(int argc, char **argv) #endif /* HAVE_PCAP_SETDIRECTION */ case 'r': +#if MESA_DUMP + printf("tcpdump_mesa not support -r arg, only support capture from sapp so far, TODO!\n"); + exit(1); +#else RFileName = optarg; +#endif break; case 's': @@ -1582,6 +1710,9 @@ main(int argc, char **argv) case 'w': WFileName = optarg; +#if MESA_DUMP + dump_to_file_flag = 1; +#endif break; case 'W': @@ -2863,9 +2994,11 @@ print_usage(void) (void)fprintf(stderr, "----------------------------------------------------------------------------------------------.\n"); (void)fprintf(stderr, -"\t\tThe follow args is customized for tcpdump_mesa:\n"); +"\t\tThe follow args is customized for tcpdump_mesa(%d):\n", tcpdump_mesa_version_VERSION_20181114); (void)fprintf(stderr, -"\t\t[ -a ] to enable perceptive mode, can detect loss packet number.\n"); +"\t\t[ -a ] enable perceptive mode, can detect loss packet number.\n"); + (void)fprintf(stderr, +"\t\t[ -g greedy-seek ] enable greedy seek to most inner IP layer, for tunnel, embed protocol.\n"); (void)fprintf(stderr, "\t\t[ -k thread-id ] to assign sapp recv thread id, support multi-range, for example: 1,3,5,7.\n"); (void)fprintf(stderr, diff --git a/udp.h b/udp.h index f9647bc..abed3c6 100644 --- a/udp.h +++ b/udp.h @@ -32,6 +32,8 @@ * * @(#)udp.h 8.1 (Berkeley) 6/10/93 */ +#ifndef _tcpdump_udp_h +#define _tcpdump_udp_h 1 /* * Udp protocol header. @@ -314,3 +316,6 @@ struct udphdr { #ifndef LWAPP_CONTROL_PORT #define LWAPP_CONTROL_PORT 12223 /* RFC 5412 */ #endif + +#endif +