This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
tsg-packetadapter/nfqnl_test.c
luwenpeng e667e19f02 TSG-7678 并联环境下实现GTP路由封堵功能
TSG-7702 支持外层IPv4且内层为IPv4的封装模式
	TSG-7703 支持外层IPv6且内层为IPv6的封装模式
	TSG-7704 支持外层IPv6且内层为IPv4的封装模式
	TSG-7705 支持外层IPv4且内层为IPv6的封装模式
2021-09-10 09:55:18 +08:00

860 lines
22 KiB
C

#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <linux/tcp.h>
#include <linux/netfilter.h> // for NF_ACCEPT
#include <libnetfilter_queue/libnetfilter_queue.h>
#include "log.h"
#define GTP_TPDU 255
#define GTP1U_PORT 2152
#define GTP1_F_MASK 0x07
#define UDP_HEADER_LEN 8
#define TCP_HEADER_LEN 20
#define TCP_OPTLENMAX 40
#define IPV4_HEADER_LEN 20
#define IPV6_HEADER_LEN 40
#define IP_GET_RAW_VER(raw_pkt) ((((raw_pkt)[0] & 0xf0) >> 4))
#define IPV6_GET_PLEN(ip6_hdr) ((uint16_t)ntohs((ip6_hdr)->ip6_hdrun.ip6_un1.ip6_un1_plen))
#define IPV6_GET_NH(ip6_hdr) ((ip6_hdr)->ip6_hdrun.ip6_un1.ip6_un1_nxt)
#define IPV6_GET_SRC_ADDR(ip6_hdr) ((ip6_hdr)->ip6_hdrun2.ip6_un2.ip6_src)
#define IPV6_GET_DST_ADDR(ip6_hdr) ((ip6_hdr)->ip6_hdrun2.ip6_un2.ip6_dst)
#define IPV4_GET_HLEN(ip4_hdr) (((ip4_hdr)->ip_verhl & 0x0f) << 2)
#define IPV4_GET_IPPROTO(ip4_hdr) ((ip4_hdr)->ip_proto)
#define IPV4_GET_IPLEN(ip4_hdr) ((uint16_t)ntohs((ip4_hdr)->ip_len))
#define IPV4_GET_SRC_ADDR(ip4_hdr) ((ip4_hdr)->ip4_hdrun1.ip4_un1.ip_src)
#define IPV4_GET_DST_ADDR(ip4_hdr) ((ip4_hdr)->ip4_hdrun1.ip4_un1.ip_dst)
#define UDP_GET_LEN(udp_hdr) ((uint16_t)ntohs((udp_hdr)->udp_len))
#define UDP_GET_SRC_PORT(udp_hdr) ((uint16_t)ntohs((udp_hdr)->udp_src_port))
#define UDP_GET_DST_PORT(udp_hdr) ((uint16_t)ntohs((udp_hdr)->udp_dst_port))
#define TCP_GET_HLEN(tcp_hdr) ((((tcp_hdr)->th_offx2 & 0xf0) >> 4) << 2)
#define TCP_GET_SRC_PORT(tcp_hdr) ((uint16_t)ntohs((tcp_hdr)->th_sport))
#define TCP_GET_DST_PORT(tcp_hdr) ((uint16_t)ntohs((tcp_hdr)->th_dport))
#define GTP1_GET_TYPE(gtp1_hdr) ((gtp1_hdr)->type)
#define GTP1_GET_FLAGS(gtp1_hdr) ((gtp1_hdr)->flags >> 5)
#define GTP1_GET_HLEN(gtp1_hdr) (((gtp1_hdr)->flags & GTP1_F_MASK) > 0 ? 12 : 8)
///////////////////////////////////////////////////////////////////////////////
// IPv4 IPv6 UDP GPT Header Struct
///////////////////////////////////////////////////////////////////////////////
typedef struct ipv6_header_s
{
union
{
struct ip6_un1_
{
uint32_t ip6_un1_flow; /* 20 bits of flow-ID */
uint16_t ip6_un1_plen; /* payload length */
uint8_t ip6_un1_nxt; /* next header */
uint8_t ip6_un1_hlim; /* hop limit */
} ip6_un1;
uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */
} ip6_hdrun;
union
{
struct
{
uint32_t ip6_src[4];
uint32_t ip6_dst[4];
} ip6_un2;
uint16_t ip6_addrs[16];
} ip6_hdrun2;
} ipv6_header_t;
typedef struct ipv4_header_s
{
uint8_t ip_verhl; // version & header length
uint8_t ip_tos;
uint16_t ip_len;
uint16_t ip_id;
uint16_t ip_off;
uint8_t ip_ttl;
uint8_t ip_proto;
uint16_t ip_csum;
union
{
struct
{
struct in_addr ip_src;
struct in_addr ip_dst;
} ip4_un1;
uint16_t ip_addrs[4];
} ip4_hdrun1;
} ipv4_header_t;
typedef struct tcp_header_s
{
uint16_t th_sport; /**< source port */
uint16_t th_dport; /**< destination port */
uint32_t th_seq; /**< sequence number */
uint32_t th_ack; /**< acknowledgement number */
uint8_t th_offx2; /**< offset and reserved */
uint8_t th_flags; /**< pkt flags */
uint16_t th_win; /**< pkt window */
uint16_t th_sum; /**< checksum */
uint16_t th_urp; /**< urgent pointer */
} __attribute__((__packed__)) tcp_header_t;
typedef struct udp_header_s
{
uint16_t udp_src_port;
uint16_t udp_dst_port;
uint16_t udp_len;
uint16_t udp_sum;
} __attribute__((__packed__)) udp_header_t;
enum gtp_version_e
{
GTP_V0 = 0,
GTP_V1,
};
/* According to 3GPP TS 29.060. */
typedef struct gtp1_header_s
{
uint8_t flags;
uint8_t type;
uint16_t length;
uint32_t tid;
} __attribute__((packed)) gtp1_header_t;
///////////////////////////////////////////////////////////////////////////////
// IPv4 IPv6 UDP GPT Header Parser
///////////////////////////////////////////////////////////////////////////////
typedef enum network_mode_s
{
NONE = 0,
IPv4 = 1,
IPv6 = 2,
TCP = 3,
UDP = 4,
} network_mode_t;
typedef struct pkt_info_s
{
uint32_t id;
uint8_t *payload;
uint32_t payload_len;
} pkt_info_t;
typedef struct ipv4_info_s
{
char src_addr[INET_ADDRSTRLEN];
char dst_addr[INET_ADDRSTRLEN];
ipv4_header_t *hdr;
uint8_t *payload;
uint32_t hdr_len;
uint32_t opts_len;
uint32_t payload_len;
} ipv4_info_t;
typedef struct ipv6_info_s
{
char src_addr[INET6_ADDRSTRLEN];
char dst_addr[INET6_ADDRSTRLEN];
ipv6_header_t *hdr;
uint8_t *payload;
uint32_t hdr_len;
uint32_t payload_len;
} ipv6_info_t;
typedef struct udp_info_s
{
uint16_t src_port;
uint16_t dst_port;
udp_header_t *hdr;
uint8_t *payload;
uint32_t hdr_len;
uint32_t payload_len;
} udp_info_t;
typedef struct tcp_info_s
{
uint16_t src_port;
uint16_t dst_port;
tcp_header_t *hdr;
uint8_t *payload;
uint32_t opt_len;
uint32_t hdr_len;
uint32_t payload_len;
} tcp_info_t;
typedef struct gtp_info_s
{
gtp1_header_t *hdr;
uint8_t *payload;
uint32_t hdr_len;
uint32_t payload_len;
} gtp_info_t;
typedef struct pkt_paser_s
{
pkt_info_t raw_pkt;
ipv4_info_t external_ipv4;
ipv6_info_t external_ipv6;
udp_info_t external_udp;
gtp_info_t external_gtp;
ipv4_info_t internal_ipv4;
ipv6_info_t internal_ipv6;
udp_info_t internal_udp;
tcp_info_t internal_tcp;
network_mode_t external_ip_version;
network_mode_t external_l4_version;
network_mode_t internal_ip_version;
network_mode_t internal_l4_version;
} pkt_paser_t;
///////////////////////////////////////////////////////////////////////////////
// Packet Parser API
///////////////////////////////////////////////////////////////////////////////
static void dump_info(pkt_paser_t *pkt_parser)
{
LOG_DEBUG("raw_pkt: {id: %u, data_len: %u}", pkt_parser->raw_pkt.id, pkt_parser->raw_pkt.payload_len);
if (pkt_parser->external_ipv4.hdr)
{
LOG_DEBUG("id: %u, external_ipv4: {src_addr:%s,dst_addr:%s,hdr_len: %u, opt_len: %u, data_len: %u}",
pkt_parser->raw_pkt.id,
pkt_parser->external_ipv4.src_addr,
pkt_parser->external_ipv4.dst_addr,
pkt_parser->external_ipv4.hdr_len,
pkt_parser->external_ipv4.opts_len,
pkt_parser->external_ipv4.payload_len);
}
if (pkt_parser->external_ipv6.hdr)
{
LOG_DEBUG("id: %u, external_ipv6: {src_addr:%s,dst_addr:%s,hdr_len: %u, data_len: %u}",
pkt_parser->raw_pkt.id,
pkt_parser->external_ipv6.src_addr,
pkt_parser->external_ipv6.dst_addr,
pkt_parser->external_ipv6.hdr_len,
pkt_parser->external_ipv6.payload_len);
}
if (pkt_parser->external_udp.hdr)
{
LOG_DEBUG("id: %u, external_udp: {src_port: %u, dst_port: %u, hdr_len: %u, data_len: %u}",
pkt_parser->raw_pkt.id,
pkt_parser->external_udp.src_port,
pkt_parser->external_udp.dst_port,
pkt_parser->external_udp.hdr_len,
pkt_parser->external_udp.payload_len);
}
if (pkt_parser->external_gtp.hdr)
{
LOG_DEBUG("id: %u, external_gtp: {hdr_len: %u, data_len: %u}",
pkt_parser->raw_pkt.id,
pkt_parser->external_gtp.hdr_len,
pkt_parser->external_gtp.payload_len);
}
if (pkt_parser->internal_ipv4.hdr)
{
LOG_DEBUG("id: %u, internal_ipv4: {src_addr:%s,dst_addr:%s,hdr_len: %u, opt_len: %u, data_len: %u}",
pkt_parser->raw_pkt.id,
pkt_parser->internal_ipv4.src_addr,
pkt_parser->internal_ipv4.dst_addr,
pkt_parser->internal_ipv4.hdr_len,
pkt_parser->internal_ipv4.opts_len,
pkt_parser->internal_ipv4.payload_len);
}
if (pkt_parser->internal_ipv6.hdr)
{
LOG_DEBUG("id: %u, interna_ipv6: {src_addr:%s,dst_addr:%s,hdr_len: %u, data_len: %u}",
pkt_parser->raw_pkt.id,
pkt_parser->internal_ipv6.src_addr,
pkt_parser->internal_ipv6.dst_addr,
pkt_parser->internal_ipv6.hdr_len,
pkt_parser->internal_ipv6.payload_len);
}
if (pkt_parser->internal_udp.hdr)
{
LOG_DEBUG("id: %u, internal_udp: {src_port: %u, dst_port: %u, hdr_len: %u, data_len: %u}",
pkt_parser->raw_pkt.id,
pkt_parser->internal_udp.src_port,
pkt_parser->internal_udp.dst_port,
pkt_parser->internal_udp.hdr_len,
pkt_parser->internal_udp.payload_len);
}
if (pkt_parser->internal_tcp.hdr)
{
LOG_DEBUG("id: %u, internal_tcp: {src_port: %u, dst_port: %u, hdr_len: %u, data_len:%u}",
pkt_parser->raw_pkt.id,
pkt_parser->internal_tcp.src_port,
pkt_parser->internal_tcp.dst_port,
pkt_parser->internal_tcp.hdr_len,
pkt_parser->internal_tcp.payload_len);
}
}
static int decode_gtp(gtp_info_t *packet, const uint8_t *data, uint32_t len)
{
if (len < sizeof(gtp1_header_t))
{
LOG_ERROR("Parser GTP Header: packet length too small %d", len);
return -1;
}
packet->hdr = (gtp1_header_t *)data;
if (GTP1_GET_FLAGS(packet->hdr) != GTP_V1)
{
LOG_ERROR("Parser GTP Header: invalid gtp flags %d", GTP1_GET_FLAGS(packet->hdr));
return -1;
}
if (GTP1_GET_TYPE(packet->hdr) != GTP_TPDU)
{
LOG_ERROR("Parser GTP Header: invalid gtp type %d", GTP1_GET_TYPE(packet->hdr));
return -1;
}
/* From 29.060: "This field shall be present if and only if any one or
* more of the S, PN and E flags are set.".
*
* If any of the bit is set, then the remaining ones also have to be set.
*/
packet->hdr_len = GTP1_GET_HLEN(packet->hdr);
packet->payload = (uint8_t *)data + packet->hdr_len;
packet->payload_len = len - packet->hdr_len;
return 0;
}
static int decode_udp(udp_info_t *packet, const uint8_t *data, uint32_t len)
{
if (len < UDP_HEADER_LEN)
{
LOG_ERROR("Parser UDP Header: packet length too small %d", len);
return -1;
}
packet->hdr = (udp_header_t *)data;
// 检查 UDP header len
if (len < UDP_GET_LEN(packet->hdr))
{
LOG_ERROR("Parser UDP Header: UDP packet too small %d", len);
return -1;
}
// 检查 UDP header len
if (len != UDP_GET_LEN(packet->hdr))
{
LOG_ERROR("Parser UDP Header: invalid UDP header length %d", UDP_GET_LEN(packet->hdr));
return -1;
}
packet->src_port = UDP_GET_SRC_PORT(packet->hdr);
packet->dst_port = UDP_GET_DST_PORT(packet->hdr);
packet->hdr_len = UDP_HEADER_LEN;
packet->payload = (uint8_t *)data + UDP_HEADER_LEN;
packet->payload_len = len - UDP_HEADER_LEN;
return 0;
}
static int decode_tcp(tcp_info_t *packet, const uint8_t *data, uint32_t len)
{
if (len < TCP_HEADER_LEN)
{
LOG_ERROR("Parser TCP Header: packet length too small %d", len);
return -1;
}
packet->hdr = (tcp_header_t *)data;
uint8_t hlen = TCP_GET_HLEN(packet->hdr);
if (len < hlen)
{
LOG_ERROR("Parser TCP Header: TCP packet too small %d", len);
return -1;
}
uint8_t tcp_opt_len = hlen - TCP_HEADER_LEN;
if (tcp_opt_len > TCP_OPTLENMAX)
{
LOG_ERROR("Parser TCP Header: invalid opt length %d", tcp_opt_len);
return -1;
}
packet->opt_len = tcp_opt_len;
packet->src_port = TCP_GET_SRC_PORT(packet->hdr);
packet->dst_port = TCP_GET_DST_PORT(packet->hdr);
packet->hdr_len = hlen;
packet->payload = (uint8_t *)data + packet->hdr_len;
packet->payload_len = len = packet->hdr_len;
return 0;
}
static int decode_ipv6(ipv6_info_t *packet, const uint8_t *data, uint32_t len)
{
if (len < IPV6_HEADER_LEN)
{
LOG_ERROR("Parser IPv6 Header: packet length too small %d", len);
return -1;
}
// 检查 IPv6 header version
if (IP_GET_RAW_VER(data) != 6)
{
LOG_ERROR("Parser IPv6 Header: unknown IP version %d", IP_GET_RAW_VER(data));
return -1;
}
packet->hdr = (ipv6_header_t *)data;
if (len < (IPV6_HEADER_LEN + IPV6_GET_PLEN(packet->hdr)))
{
LOG_ERROR("Parser IPv6 Header: trunc packet");
return -1;
}
if (len != (IPV6_HEADER_LEN + IPV6_GET_PLEN(packet->hdr)))
{
LOG_ERROR("Parser IPv6 Header: invalid payload length %d", IPV6_GET_PLEN(packet->hdr));
return -1;
}
inet_ntop(AF_INET6, &IPV6_GET_SRC_ADDR(packet->hdr), packet->src_addr, sizeof(packet->src_addr));
inet_ntop(AF_INET6, &IPV6_GET_DST_ADDR(packet->hdr), packet->dst_addr, sizeof(packet->dst_addr));
packet->hdr_len = IPV6_HEADER_LEN;
packet->payload = (uint8_t *)data + packet->hdr_len;
packet->payload_len = len - packet->hdr_len;
return 0;
}
static int decode_ipv4(ipv4_info_t *packet, const uint8_t *data, uint32_t len)
{
// 检查包长是否大于 IPv4 header
if (len < IPV4_HEADER_LEN)
{
LOG_ERROR("Parser IPv4 Header: packet length too small %d", len);
return -1;
}
// 检查 IPv4 header version
if (IP_GET_RAW_VER(data) != 4)
{
LOG_ERROR("Parser IPv4 Header: unknown IP version %d", IP_GET_RAW_VER(data));
return -1;
}
packet->hdr = (ipv4_header_t *)data;
// 检查 IPv4 header length
if (IPV4_GET_HLEN(packet->hdr) < IPV4_HEADER_LEN)
{
LOG_ERROR("Parser IPv4 Header: invalid IP header length %d", IPV4_GET_HLEN(packet->hdr));
return -1;
}
// 检查 IPv4 header total length
if (IPV4_GET_IPLEN(packet->hdr) < IPV4_GET_HLEN(packet->hdr))
{
LOG_ERROR("Parser IPv4 Header: invalid IP header total length %d", IPV4_GET_IPLEN(packet->hdr));
return -1;
}
// 检查是否 IP 分片
if (len < IPV4_GET_IPLEN(packet->hdr))
{
LOG_ERROR("Parser IPv4 Header: trunc packet");
return -1;
}
inet_ntop(AF_INET, &IPV4_GET_SRC_ADDR(packet->hdr), packet->src_addr, sizeof(packet->src_addr));
inet_ntop(AF_INET, &IPV4_GET_DST_ADDR(packet->hdr), packet->dst_addr, sizeof(packet->dst_addr));
packet->hdr_len = IPV4_GET_HLEN(packet->hdr);
packet->opts_len = packet->hdr_len - IPV4_HEADER_LEN;
packet->payload_len = len - packet->hdr_len;
packet->payload = (uint8_t *)data + packet->hdr_len;
return 0;
}
static int decode_internal_ip_pkt(pkt_paser_t *pkt_parser, const uint8_t *data, uint32_t len)
{
int next_protocol = 0;
uint8_t *payload = NULL;
uint32_t payload_len = 0;
// IPv4/IPv6
if (len < IPV4_HEADER_LEN)
{
LOG_ERROR("Parser Internal Raw header: packet length too small %d", len);
return -1;
}
if (IP_GET_RAW_VER(data) == 4)
{
if (decode_ipv4(&(pkt_parser->internal_ipv4), data, len) == -1)
{
return -1;
}
pkt_parser->internal_ip_version = IPv4;
payload = pkt_parser->internal_ipv4.payload;
payload_len = pkt_parser->internal_ipv4.payload_len;
next_protocol = IPV4_GET_IPPROTO(pkt_parser->internal_ipv4.hdr);
}
else if (IP_GET_RAW_VER(data) == 6)
{
if (decode_ipv6(&(pkt_parser->internal_ipv6), data, len) == -1)
{
return -1;
}
pkt_parser->internal_ip_version = IPv6;
payload = pkt_parser->internal_ipv6.payload;
payload_len = pkt_parser->internal_ipv6.payload_len;
next_protocol = IPV6_GET_NH(pkt_parser->internal_ipv6.hdr);
}
else
{
LOG_ERROR("Unknown Internal IP version %d", IP_GET_RAW_VER(data));
return -1;
}
// TCP/UDP
if (next_protocol == IPPROTO_UDP)
{
if (decode_udp(&(pkt_parser->internal_udp), payload, payload_len) == -1)
{
return -1;
}
pkt_parser->internal_l4_version = UDP;
return 0;
}
else if (next_protocol == IPPROTO_TCP)
{
if (decode_tcp(&(pkt_parser->internal_tcp), payload, payload_len) == -1)
{
return -1;
}
pkt_parser->internal_l4_version = TCP;
return 0;
}
else
{
LOG_ERROR("Unknown Internal L4 next_protocol version %d", next_protocol);
return -1;
}
}
static int decode_external_ip_pkt(pkt_paser_t *pkt_parser, const uint8_t *data, uint32_t len)
{
int next_protocol = 0;
uint8_t *payload = NULL;
uint32_t payload_len = 0;
// IPv4/IPv6
if (len < IPV4_HEADER_LEN)
{
LOG_ERROR("Parser External Raw header: packet length too small %d", len);
return -1;
}
if (IP_GET_RAW_VER(data) == 4)
{
if (decode_ipv4(&(pkt_parser->external_ipv4), data, len) == -1)
{
return -1;
}
pkt_parser->external_ip_version = IPv4;
payload = pkt_parser->external_ipv4.payload;
payload_len = pkt_parser->external_ipv4.payload_len;
next_protocol = IPV4_GET_IPPROTO(pkt_parser->external_ipv4.hdr);
}
else if (IP_GET_RAW_VER(data) == 6)
{
if (decode_ipv6(&(pkt_parser->external_ipv6), data, len) == -1)
{
return -1;
}
pkt_parser->external_ip_version = IPv6;
payload = pkt_parser->external_ipv6.payload;
payload_len = pkt_parser->external_ipv6.payload_len;
next_protocol = IPV6_GET_NH(pkt_parser->external_ipv6.hdr);
}
else
{
LOG_ERROR("Unknown External IP version %d", IP_GET_RAW_VER(data));
return -1;
}
// TCP/UDP
if (next_protocol == IPPROTO_UDP)
{
if (decode_udp(&(pkt_parser->external_udp), payload, payload_len) == -1)
{
return -1;
}
pkt_parser->external_l4_version = UDP;
}
else if (next_protocol == IPPROTO_TCP)
{
pkt_parser->external_l4_version = TCP;
LOG_ERROR("Unknown External L4 next_protocol version %d", next_protocol);
return -1;
}
else
{
LOG_ERROR("Unknown External L4 next_protocol version %d", next_protocol);
return -1;
}
// GTP
if (decode_gtp(&(pkt_parser->external_gtp), pkt_parser->external_udp.payload, pkt_parser->external_udp.payload_len) == -1)
{
return -1;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// NFQ API
///////////////////////////////////////////////////////////////////////////////
/*
* nfmsg : message objetc that contains the packet
* nfa : Netlink packet data handle
*/
static int packet_handler_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data)
{
int offest = 0;
int raw_ip_fd = 0;
int packet_len = 0;
pkt_paser_t pkt_parser = {0};
unsigned char *packet_data = NULL;
struct nfqnl_msg_packet_hdr *packet_hdr = NULL;
struct sockaddr_in saddr = {0};
packet_hdr = nfq_get_msg_packet_hdr(nfa);
if (packet_hdr == NULL)
{
LOG_ERROR("Failed at nfq_get_msg_packet_hdr()");
goto end;
}
packet_len = nfq_get_payload(nfa, &packet_data);
if (packet_len <= 0)
{
LOG_ERROR("Failed at nfq_get_payload()");
goto end;
}
pkt_parser.raw_pkt.id = ntohl(packet_hdr->packet_id);
pkt_parser.raw_pkt.payload = packet_data;
pkt_parser.raw_pkt.payload_len = packet_len;
if (decode_external_ip_pkt(&pkt_parser, pkt_parser.raw_pkt.payload, pkt_parser.raw_pkt.payload_len) == -1)
{
goto end;
}
if (decode_internal_ip_pkt(&pkt_parser, pkt_parser.external_gtp.payload, pkt_parser.external_gtp.payload_len) == -1)
{
goto end;
}
/*
* NF_DROP : discarded the packet
* NF_ACCEPT : the packet passes, continue iterations
* NF_QUEUE : inject the packet into a different queue (the target queue number is in the high 16 bits of the verdict)
* NF_REPEAT : iterate the same cycle once more
* NF_STOP : accept, but don't continue iterations
*/
// nfq_set_verdict()
// nfq_set_verdict2()
// nfq_set_verdict_batch()
// nfq_set_verdict_batch2()
// nfq_set_verdict_mark()
if (pkt_parser.external_ip_version == IPv4)
{
offest += pkt_parser.external_ipv4.hdr_len;
}
if (pkt_parser.external_ip_version == IPv6)
{
offest += pkt_parser.external_ipv6.hdr_len;
}
offest += pkt_parser.external_udp.hdr_len;
offest += pkt_parser.external_gtp.hdr_len;
dump_info(&pkt_parser);
LOG_DEBUG("Offset : %d", offest);
if (offest > 0)
{
if ((pkt_parser.external_ip_version == IPv4 && pkt_parser.internal_ip_version == IPv4) || (pkt_parser.external_ip_version == IPv6 && pkt_parser.internal_ip_version == IPv6))
{
return nfq_set_verdict(qh, pkt_parser.raw_pkt.id, NF_ACCEPT, packet_len - offest, packet_data + offest);
}
if (pkt_parser.external_ip_version == IPv4 && pkt_parser.internal_ip_version == IPv6)
{
saddr.sin_family = AF_INET6;
saddr.sin_addr.s_addr = inet_addr(pkt_parser.internal_ipv6.dst_addr);
}
else if (pkt_parser.external_ip_version == IPv6 && pkt_parser.internal_ip_version == IPv4)
{
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr(pkt_parser.internal_ipv4.dst_addr);
}
raw_ip_fd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
if (sendto(raw_ip_fd, packet_data + offest, packet_len - offest, 0, (struct sockaddr *)&saddr, sizeof(saddr)) == -1)
{
LOG_ERROR("Failed at send(), %d: %s", errno, strerror(errno));
goto end;
}
return nfq_set_verdict(qh, pkt_parser.raw_pkt.id, NF_DROP, 0, NULL);
}
end:
return nfq_set_verdict(qh, pkt_parser.raw_pkt.id, NF_ACCEPT, 0, NULL);
}
/*
* doc : http://www.netfilter.org/projects/libnetfilter_queue/doxygen/html/
* Library setup : http://www.netfilter.org/projects/libnetfilter_queue/doxygen/html/group__LibrarySetup.html
* Queue handling : http://www.netfilter.org/projects/libnetfilter_queue/doxygen/html/group__Queue.html
* Message parsing : http://www.netfilter.org/projects/libnetfilter_queue/doxygen/html/group__Parsing.html
*/
int main(int argc, char **argv)
{
int fd;
int rv;
uint32_t queue = 1;
struct nfq_handle *handle;
struct nfq_q_handle *q_handle;
char buf[4096] __attribute__((aligned));
if (argc == 2)
{
queue = atoi(argv[1]);
if (queue > 65535)
{
fprintf(stderr, "Usage: %s [<0-65535>]\n", argv[0]);
return 0;
}
}
LOG_DEBUG("Using queue: %d", queue);
handle = nfq_open();
if (handle == NULL)
{
LOG_ERROR("Failed at nfq_open(), %d: %s", errno, strerror(errno));
goto error;
}
if (nfq_unbind_pf(handle, AF_INET) < 0)
{
LOG_ERROR("Failed at nfq_unbind_pf(), %d: %s", errno, strerror(errno));
goto error;
}
if (nfq_bind_pf(handle, AF_INET) < 0)
{
LOG_ERROR("Failed at nfq_bind_pf(), %d: %s", errno, strerror(errno));
goto error;
}
q_handle = nfq_create_queue(handle, queue, &packet_handler_cb, NULL);
if (q_handle == NULL)
{
LOG_ERROR("Failed at nfq_create_queue(), %d: %s", errno, strerror(errno));
goto error;
}
/*
* NFQNL_COPY_NONE - noop, do not use it
* NFQNL_COPY_META - copy only packet metadata
* NFQNL_COPY_PACKET - copy entire packet
*/
if (nfq_set_mode(q_handle, NFQNL_COPY_PACKET, 0xffff) < 0)
{
LOG_ERROR("Failed at nfq_set_mode(NFQNL_COPY_PACKET), %d: %s", errno, strerror(errno));
goto error;
}
if (nfq_set_queue_maxlen(q_handle, 65535) < 0)
{
LOG_ERROR("Failed at nfq_set_queue_maxlen(65535), %d: %s", errno, strerror(errno));
goto error;
}
LOG_DEBUG("Waiting for packets...");
fd = nfq_fd(handle);
for (;;)
{
if ((rv = recv(fd, buf, sizeof(buf), 0)) >= 0)
{
nfq_handle_packet(handle, buf, rv);
continue;
}
/*
* if your application is too slow to digest the packets that
* are sent from kernel-space, the socket buffer that we use
* to enqueue packets may fill up returning ENOBUFS. Depending
* on your application, this error may be ignored. Please, see
* the doxygen documentation of this library on how to improve
* this situation.
*/
if (rv < 0 && errno == ENOBUFS)
{
LOG_ERROR("Losing packets !!!");
continue;
}
LOG_ERROR("Failed at recv(), %d: %s", errno, strerror(errno));
break;
}
error:
if (q_handle)
{
nfq_destroy_queue(q_handle);
}
if (handle)
{
nfq_close(handle);
}
return 0;
}