diff --git a/source/mk/bpf.mk b/source/mk/bpf.mk index 883cc7f4bf95c0517d5d313609b880c1d98e72e1..4222fd5dc7da7f1246b290ef64f808baeffb5162 100644 --- a/source/mk/bpf.mk +++ b/source/mk/bpf.mk @@ -4,7 +4,7 @@ BPFTOOL ?= $(SRC)/lib/internal/ebpf/tools/bpftool APPS_DIR := $(abspath .) prefix ?= /usr/local ARCH := $(shell uname -m | sed 's/x86_64/x86/') -LIBBPF_OBJ := $(OBJ_LIB_PATH)/libbpf.a +LIBBPF_OBJ += $(OBJ_LIB_PATH)/libbpf.a ifeq ($(KERNEL_DEPEND), Y) OUTPUT := $(OBJ_TOOLS_PATH) diff --git a/source/tools/detect/net_diag/tcpping/Makefile b/source/tools/detect/net_diag/tcpping/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ab91f7d5ca95f3885b465262cbdb87c89a44519d --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/Makefile @@ -0,0 +1,12 @@ +LDFLAGS += -lz -pthread -ldl +#CFLAGS += -std=c++11 -static +INCLUDES += -I$(SRC)/../out/bpf -I$(SRC)/tools/detect/net_diag/tcpping/include -I$(SRC)/lib/internal/ebpf/libbpf/src + +LIBBPF_OBJ := $(SRC)/tools/detect/net_diag/tcpping/lib/libnet.a +newdirs := $(shell find src/ -type d) +newdirs += $(shell find bpf/ -type d) +csrcs := $(shell find ./src -name "*.c") +bpfsrcs := $(wildcard bpf/*.bpf.c) +target := tcpping + +include $(SRC)/mk/bpf.mk diff --git a/source/tools/detect/net_diag/tcpping/README.md b/source/tools/detect/net_diag/tcpping/README.md new file mode 100644 index 0000000000000000000000000000000000000000..06a1d0bd9c7b46cdd41cbc00267be6e44a15fa34 --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/README.md @@ -0,0 +1,102 @@ +# tcpping +tcpping是一个基于eBPF实现的网络延迟探测定界工具,该工具实现了一个基于TCP协议的网络延迟探测协议,通过发送和解析探测报文来定位报文在不同传输阶段的延迟信息。 +## 构建 +### 环境依赖 + +#### libnet + +``` +libnet 源码: +目前程序中将源码编译成libnet.a放在lib路径下,链接到tcpping中 +``` + +### 编译 +``` +./configure --enable-target-tcpping +./configure --enable-target-btf +sudo make +编译生成的二进制tcpping在out路径下, 在tcpping路径下已经放置了编译好的二进制文件 +``` +## 运行 +要运行tcpping,请保证如下位置有内核btf相关文件: +- /sys/kernel/btf/vmlinux +- /boot/vmlinux- +- /lib/modules//vmlinux- +- /lib/modules//build/vmlinux +- /usr/lib/modules//kernel/vmlinux +- /usr/lib/debug/boot/vmlinux- +- /usr/lib/debug/boot/vmlinux-.debug +- /usr/lib/debug/lib/modules//vmlinux +- 程序中默认会优先在sysak中寻找 + +## 使用 +### 命令行参数 +``` +Usage: tcpping [OPTIONS] + +Options: + + -h,--help 帮助信息 + -s,--source ip 源ip + -d,--dest ip 目的ip + -c,--package count 探测报文数量,默认无限 + -t,--interval_us 报文发送间隔时间(ms), 默认1ms + -p,--source port 源端口,默认30330 + -q,--dest port 目的端口,默认80 + -o,--output image/json -o **.json 指定路径输出json格式,不指定-o + 控制台输出 + -u,--cpu affinity 指定cpu运行,默认cpu0, -1 不指定cpu +``` +### 使用示例 +``` +sysak tcpping -s 11.160.62.45 -d 11.160.62.49 -c 10 +``` +发送10个报文,输出到控制台,结果如下 +``` ++-------------------tcp-trace---------------------+ +| seq: 9 unit:usec | +| +-------+ 148 +---------------+ | +| | local | ---------> | 11.160.62.49| | +| +-------+ +---------------+ | +| | user | | +| ------------------------ +--------+ | +| | | | | | +| 2 | trans layer| | | | +| ------------------------ | | | +| | | | | | +| 6 | ip layer | 3 | | | +| |----------------- | ^ | +| | | v | | +| | dev layer | 1 | | | +| ------|------------|---- | | | +| v | 134 | | | +| | +-------<-----+ | | +| +---------------->------------------+ | +| | ++-------------------------------------------------+ +``` +sysak tcpping -s 11.160.62.45 -d 11.160.62.49 -c 10 -o /tmp/tcpping.json +``` +发送10个报文,输出到/tmp/tccping.json文件中 +``` +{ + "data": { + "seq": 0, + "t_trans": 8, + "t_ip": 34, + "r_remote": 302, + "r_dev": 9, + "r_ip": 24, + "delta": 379 + }, + "data": { + "seq": 1, + "t_trans": 3, + "t_ip": 10, + "r_remote": 206, + "r_dev": 1, + "r_ip": 6, + "delta": 228 + } +} +``` diff --git a/source/tools/detect/net_diag/tcpping/bpf/tcpping.bpf.c b/source/tools/detect/net_diag/tcpping/bpf/tcpping.bpf.c new file mode 100644 index 0000000000000000000000000000000000000000..6aec66a0b9725ab3b07dd59b9b9862c0176a98ce --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/bpf/tcpping.bpf.c @@ -0,0 +1,148 @@ +/* + * Author: Chen Tao + * Create: Mon Jan 17 14:12:20 2022 + */ +#include +#include +#include +#include +//#include +#include "bpf_common.h" + +/* + * recv probe func: net_receive_skb、ip_rcv、tcp_v4_rcv + * send probe func: tcp_transmit_skb、ip_finish_output、dev_queue_xmit + */ +struct { + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); + __type(key, int); + __type(value, int); +} perf_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(max_entries, 10000); + __type(key, struct tcptrace_map_key); + __type(value, struct tcptrace_map_value); +} pt_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1); + __type(key, int); + __type(value, struct tuple_info); +} tuple_map SEC(".maps"); + +/* +struct { + __uint(BPF_MAP_TYPE_PERF_EVENT_ARRAY); + __type(key, int); + __type(value, int); +} perf_map SEC(".maps"); +*/ + +SEC("kprobe/raw_sendmsg") +int __ip_queue_xmit_hook(struct pt_regs *ctx) +{ + struct tuple_info *tuple = NULL; + struct sockaddr_in *usin = NULL; + + tuple = get_tuple_info(&tuple_map, PORT_VARS); + if (!tuple) { + return 0; + } + + struct msghdr *msg = (void *)PT_REGS_PARM2(ctx); + tag_raw_timestamp(&pt_map, msg, PT_KERN_RAW_SENDMSG, TCPTRACE_DIRECTION_OUT, tuple, + false, ctx, &perf_map); + return 0; +} +/* +SEC("kprobe/ip_finish_output2") +int ip_finish_output_hook(struct pt_regs *ctx) +{ + struct tuple_info *tuple; + + tuple = get_tuple_info(&tuple_map, PORT_VARS); + if (!tuple) { + return 0; + } + //struct sk_buff *skb = (void *)PT_REGS_PARM2(ctx); + struct sock *sk = (void *)PT_REGS_PARM2(ctx); + //tag_sock_timestamp(&pt_map, sk, PT_KERN_IP_FIN_OUTPUT, TCPTRACE_DIRECTION_OUT, tuple, + // false, ctx, &perf_map); + + return 0; +} +*/ + +SEC("kprobe/__dev_queue_xmit") +int dev_queue_xmit_hook(struct pt_regs *ctx) +{ + struct tuple_info *tuple = NULL; + + tuple = get_tuple_info(&tuple_map, PORT_VARS); + if (!tuple) { + return 0; + } + struct sk_buff *skb = (void *)PT_REGS_PARM1(ctx); + tag_timestamp(&pt_map, skb, PT_KERN_DEV_QUE_XMIT, TCPTRACE_DIRECTION_OUT, tuple, + true, ctx, &perf_map); + + return 0; +} + +SEC("kprobe/tcp_v4_rcv") +int tcp_v4_rcv_hook(struct pt_regs *ctx) +{ + struct tuple_info *tuple; + + tuple = get_tuple_info(&tuple_map, PORT_VARS); + if (!tuple) { + return 0; + } + + struct sk_buff *skb = (void *)PT_REGS_PARM1(ctx); + tag_timestamp(&pt_map, skb, PT_KERN_TCP_V4_RCV, TCPTRACE_DIRECTION_IN, tuple, + true, ctx, &perf_map); + return 0; +} + +SEC("kprobe/ip_rcv") +int ip_rcv_hook(struct pt_regs *ctx) +{ + struct tuple_info *tuple; + + tuple = get_tuple_info(&tuple_map, PORT_VARS); + if (!tuple) { + return 0; + } + + struct sk_buff *skb = (void *)PT_REGS_PARM1(ctx); + tag_timestamp(&pt_map, skb, PT_KERN_IP_RCV, TCPTRACE_DIRECTION_IN, tuple, + false, ctx, &perf_map); + + return 0; +} + +struct netif_rx_args +{ + uint64_t pad; + struct sk_buff *skb; +}; +SEC("tracepoint/net/netif_receive_skb") +int netif_rx_hook(struct netif_rx_args *args) +{ + struct tuple_info *tuple; + + tuple = get_tuple_info(&tuple_map, PORT_VARS); + if (!tuple) { + return 0; + } + + tag_timestamp(&pt_map, args->skb, PT_KERN_NET_RECV_SKB, TCPTRACE_DIRECTION_IN, tuple, + false, args, &perf_map); + return 0; +} + +char LICENSE[] SEC("license") = "GPL"; diff --git a/source/tools/detect/net_diag/tcpping/include/bpf_common.h b/source/tools/detect/net_diag/tcpping/include/bpf_common.h new file mode 100644 index 0000000000000000000000000000000000000000..6ed7030d07d6472684210fbede6824a2371dc40f --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/include/bpf_common.h @@ -0,0 +1,322 @@ +/* + * Author: Chen Tao + * Create: Mon Jan 17 14:12:20 2022 + */ +#ifndef TCPTRACE_COMMON_H +#define TCPTRACE_COMMON_H +//#include "../vmlinux/vmlinux.h" +#include +#include "data_define.h" +#include + + +#define ntohs(x) (u16)__builtin_bswap16((u16)(x)) +#define ntohl(x) (u32)__builtin_bswap32((u32)(x)) + +#define tcp_bpf_printk(fmt, ...) \ +({ \ + char ____fmt[] = fmt; \ + bpf_trace_printk(____fmt, sizeof(____fmt), \ + ##__VA_ARGS__); \ +}) \ + +#define BPF_ANY 0 +#ifndef NULL +#define NULL ((void*)0) +#endif + +#define OFFSET_OF(type, member) (unsigned long)(&(((type*)0)->member)) +#define SKB_OFFSET_DATA OFFSET_OF(struct sk_buff, data) +#define SKB_OFFSET_HEAD OFFSET_OF(struct sk_buff, head) +#define SKB_OFFSET_TRANSPORT_HEADER OFFSET_OF(struct sk_buff, transport_header) +#define SKB_OFFSET_NETWORK_HEADER OFFSET_OF(struct sk_buff, network_header) + +static inline void tcptrace_map_value_clear(struct tcptrace_map_value *ptmv) +{ + int i; +#pragma unroll + for(i = 0; i < TCPTRACE_MAP_ENTRY_NUM; ++i) { + ptmv->entries[i].function_id = 0; + ptmv->entries[i].ns = 0; + ptmv->entries[i].padding = 0; + } +} + +static inline void tcptrace_map_value_fill(struct tcptrace_map_value *ptmv, + struct tcptrace_map_value *map) +{ + int i; +#pragma unroll + for(i = 0; i < TCPTRACE_MAP_ENTRY_NUM; ++i) { + map->entries[i].function_id = ptmv->entries[i].function_id; + map->entries[i].ns = ptmv->entries[i].ns; + map->entries[i].padding = ptmv->entries[i].padding; +#ifdef DEBUG + tcp_bpf_printk("func id:%d, ns:%llu\n", ptmv->entries[i].function_id, + ptmv->entries[i].ns); +#endif + } +} + +static inline void update_map_with_new_entry(void *map, struct tcptrace_map_key *key, + int direction, u32 function_id) +{ + struct tcptrace_map_value ptmv; + + tcptrace_map_value_clear(&ptmv); + ptmv.entries[function_id].function_id = function_id; + ptmv.entries[function_id].ns = bpf_ktime_get_ns(); + ptmv.entries[function_id].padding = direction; + bpf_map_update_elem(map, key, &ptmv, BPF_ANY); +} + +static inline void +update_map_with_exist_entry(struct tcptrace_map_value *ptmv, u32 function_id, + int direction) +{ + int idx = 0; + u64 ns; + + ns = bpf_ktime_get_ns(); + if (ptmv->entries[function_id].function_id && + (ptmv->entries[0].ns + TCPTRACE_MAX_RTT_NS) <= ns) { + tcptrace_map_value_clear(ptmv); + idx = 0; + goto ok; + } + +ok: + ptmv->entries[function_id].function_id = function_id; + ptmv->entries[function_id].ns = ns; + ptmv->entries[function_id].padding = direction; +} + +static inline int tcptrace_packet_raw_check(struct msghdr *msg, + struct tuple_info *tuple, + u32 function_id, + int direction, + struct tcptrace_map_key *key) +{ + u32 dst_ip; + char *ptr = NULL; + struct sockaddr_in *usin = NULL; + + BPF_CORE_READ_INTO(&usin, msg, msg_name); + BPF_CORE_READ_INTO(&dst_ip, usin, sin_addr); + + if (dst_ip != tuple->dst_ip) + return 0; + + return 1; +} + +static inline int tcptrace_packet_sock_check(struct sock *sk, + struct tuple_info *tuple, + u32 function_id, + int direction, + struct tcptrace_map_key *key) +{ + u16 src_port = 0, dst_port; + u32 src_ip, dst_ip; + //u8 protocol; + char *ptr = NULL; + + BPF_CORE_READ_INTO(&src_ip, sk, __sk_common.skc_rcv_saddr); + BPF_CORE_READ_INTO(&dst_ip, sk, __sk_common.skc_daddr); + BPF_CORE_READ_INTO(&dst_port, sk, __sk_common.skc_dport); + + if (direction == TCPTRACE_DIRECTION_OUT) { + if ((dst_ip != tuple->dst_ip) || (src_ip != tuple->src_ip) || + (dst_port != tuple->dst_port) || + (src_port != tuple->src_port)) + return 0; + } else if (direction == TCPTRACE_DIRECTION_IN) { + if ((src_ip != tuple->dst_ip) || (dst_ip != tuple->src_ip) || + (src_port != tuple->dst_port) || + (dst_port != tuple->src_port)) + return 0; + } else { + return 0; + } + + return 1; +} + +static inline int tcptrace_packet_check(struct sk_buff *skb, + struct tuple_info *tuple, + u32 function_id, + int direction, + struct tcptrace_map_key *key) +{ + struct iphdr *piph; + struct iphdr iph; + + struct tcphdr *ptcph; + struct tcphdr tcph; + u16 network_header; + void *head = NULL; + u16 src_port, dst_port; + u32 src_ip, dst_ip; + char *ptr = NULL; + + if (bpf_probe_read(&network_header, sizeof(network_header), + (void *)(skb)+SKB_OFFSET_NETWORK_HEADER)) { + tcp_bpf_printk("read network_header failed, func id:%u\n, network_header:%u", function_id, network_header); + return 0; + } + if (bpf_probe_read(&head, sizeof(head), (void *)(skb)+SKB_OFFSET_HEAD)) { + tcp_bpf_printk("read head failed, func id:%u\n, head:%p", function_id, head); + return 0; + } + /* 发包流程中2、3层获取不到头部信息 */ + piph = (struct iphdr*)(head+network_header); + if (bpf_probe_read(&iph, sizeof(iph), piph)) { + tcp_bpf_printk("read ipheader failed, func id:%u, piph:%p\n", function_id, piph); + tcp_bpf_printk("read ipheader failed, head:%p, neteork_header:%u\n", head, network_header); + return 0; + } + src_ip = iph.saddr; + dst_ip = iph.daddr; + + if (iph.protocol != IPPROTO_TCP) + return 0; + + ptcph = (struct tcphdr *)((void *)(piph) + iph.ihl * 4); + if (bpf_probe_read(&tcph, sizeof(tcph), ptcph)) { + tcp_bpf_printk("read tcp header failed, func id:%u\n", function_id); + return 0; + } + dst_port = ntohs(tcph.dest); + src_port = ntohs(tcph.source); +#ifdef DEBUG + tcp_bpf_printk("1===src_port:%u: dst_port:%u, func id:%u\n", src_port, dst_port, function_id); + tcp_bpf_printk("1===src_ip:%u, dst_ip:%u\n", src_ip, dst_ip); + tcp_bpf_printk("2===tuple src_port%u, dst_port:%u\n", tuple->src_port, tuple->dst_port); + tcp_bpf_printk("2===tuple src_ip:%u, dst_ip:%u\n", tuple->src_ip, tuple->dst_ip); +#endif + + if (direction == TCPTRACE_DIRECTION_OUT) { + /* 根据四元组确定trace报文 */ + if ((dst_ip != tuple->dst_ip) || (src_ip != tuple->src_ip) || + (dst_port != tuple->dst_port) || + (src_port != tuple->src_port)) + return 0; + } else if (direction == TCPTRACE_DIRECTION_IN) { + if ((src_ip != tuple->dst_ip) || (dst_ip != tuple->src_ip) || + (src_port != tuple->dst_port) || + (dst_port != tuple->src_port)) + return 0; + } else { + return 0; + } + + /* 发包流程中二层和三层没有seq有效信息,因此这里默认为0来识别 */ + if (function_id == PT_KERN_DEV_QUE_XMIT) { + key->seq = 0; + } else { + key->seq = tcph.seq; + } + + return 1; +} + +__attribute__((always_inline)) static inline struct tuple_info* get_tuple_info(void *map, int key){ + struct tuple_info *ret = bpf_map_lookup_elem(map, &key); + if (!ret) { + return NULL; + } + return ret; +} + +__attribute__((always_inline)) static inline void set_tuple_info(void *map, int key, int value){ + bpf_map_update_elem(map, &key, &value, BPF_ANY); +} + +__attribute__((always_inline)) static inline int tag_raw_timestamp(void *map, + struct msghdr *msg, + u32 function_id, + int direction, + struct tuple_info *tuple, + bool report, + void *ctx, + void *perf_map) +{ + struct tcptrace_map_key key = {0}; + struct tcptrace_map_value *ptmv = NULL; + struct tcptrace_map_value value = {0}; + + if (!tcptrace_packet_raw_check(msg, tuple, function_id, direction, &key)) + return -1; + + update_map_with_new_entry(map, &key, direction, function_id); + + return 0; +} + +__attribute__((always_inline)) static inline int tag_sock_timestamp(void *map, + struct sock *sk, + u32 function_id, + int direction, + struct tuple_info *tuple, + bool report, + void *ctx, + void *perf_map) +{ + struct tcptrace_map_key key = {0}; + struct tcptrace_map_value *ptmv = NULL; + struct tcptrace_map_value value = {0}; + + if (!tcptrace_packet_sock_check(sk, tuple, function_id, direction, &key)) + return -1; + + ptmv = bpf_map_lookup_elem(map, &key); + if (!ptmv) { + update_map_with_new_entry(map, &key, direction, function_id); + } else { + update_map_with_exist_entry(ptmv, function_id, direction); + if (report) { + bpf_perf_event_output(ctx, perf_map, BPF_F_CURRENT_CPU, ptmv, + sizeof(struct tcptrace_map_value)); + bpf_map_delete_elem(map, &key); + } + + } + + return 0; +} + +__attribute__((always_inline)) static inline int tag_timestamp(void *map, + struct sk_buff *skb, + u32 function_id, + int direction, + struct tuple_info *tuple, + bool report, + void *ctx, + void *perf_map) +{ + struct tcptrace_map_key key = {0}; + struct tcptrace_map_value *ptmv = NULL; + struct tcptrace_map_value value = {0}; + + if (!tcptrace_packet_check(skb, tuple, function_id, direction, &key)) + return -1; +#ifdef DEBUG + tcp_bpf_printk("skb seq:%u, func id:%u\n", key.seq, function_id); +#endif + ptmv = bpf_map_lookup_elem(map, &key); + if (!ptmv) { + update_map_with_new_entry(map, &key, direction, function_id); + } else { + update_map_with_exist_entry(ptmv, function_id, direction); + if (report) { + tcptrace_map_value_fill(ptmv, &value); + bpf_perf_event_output(ctx, perf_map, BPF_F_CURRENT_CPU, ptmv, + sizeof(struct tcptrace_map_value)); + bpf_map_delete_elem(map, &key); + } + + } + + return 0; +} +#endif //TCPTRACE_COMMON_H diff --git a/source/tools/detect/net_diag/tcpping/include/cJSON.h b/source/tools/detect/net_diag/tcpping/include/cJSON.h new file mode 100644 index 0000000000000000000000000000000000000000..e97e5f4cdc4c97cd734bb55cf86d660b388c2fa4 --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/include/cJSON.h @@ -0,0 +1,293 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif + +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) +CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type CJSON_STDCALL +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL +#endif +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 14 + +#include + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef struct cJSON_Hooks +{ + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); +} cJSON_Hooks; + +typedef int cJSON_bool; + +/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + +/* returns the version of cJSON as a string */ +CJSON_PUBLIC(const char*) cJSON_Version(void); + +/* Supply malloc, realloc and free functions to cJSON */ +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); + +/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); + +/* Render a cJSON entity to text for transfer/storage. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. */ +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); +/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ +/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); +/* Delete a cJSON entity and all subentities. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); + +/* Returns the number of items in an array (or object). */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); +/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); +/* Get item "string" from object. Case insensitive. */ +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + +/* Check item type and return its value */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); + +/* These functions check the type of an item */ +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + +/* These calls create a cJSON item of the appropriate type. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); +/* raw json */ +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); +/* Create an object/array that only references it's elements so + * they will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); + +/* These utilities create an Array of count items. + * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); + +/* Append item to the specified array/object. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + +/* Remove/Detach items from Arrays/Objects. */ +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + +/* Update array items. */ +CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will + * need to be released. With recurse!=0, it will duplicate any children connected to the item. + * The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + +/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. + * The input pointer json cannot point to a read-only address area, such as a string constant, + * but should point to a readable and writable adress area. */ +CJSON_PUBLIC(void) cJSON_Minify(char *json); + +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) +/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ +CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); + +/* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + +/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ +CJSON_PUBLIC(void *) cJSON_malloc(size_t size); +CJSON_PUBLIC(void) cJSON_free(void *object); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/tools/detect/net_diag/tcpping/include/data_define.h b/source/tools/detect/net_diag/tcpping/include/data_define.h new file mode 100644 index 0000000000000000000000000000000000000000..27ed10eb265fa2d7e92af71ac4a6d5f350fadd76 --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/include/data_define.h @@ -0,0 +1,58 @@ +/* + * Author: Chen Tao + * Create: Mon Jan 17 14:12:20 2022 + */ + +#ifndef TCPTRACE_DATA_DEFINE_H +#define TCPTRACE_DATA_DEFINE_H + +#define TCPTRACE_MAP_ENTRY_NUM 8 +#define TCPTRACE_MAX_RTT_NS 10000000000UL + +enum TCPTRACE_VARS { + PORT_VARS=0, +}; + +enum TCPTRACE_DIRCTION { + TCPTRACE_DIRECTION_OUT = 0, + TCPTRACE_DIRECTION_IN, +}; + +struct tuple_info { + uint32_t src_ip; + uint32_t dst_ip; + uint16_t src_port; + uint16_t dst_port; + uint32_t protol; +}; +/* + * function_id in tcptrace_map_entry + */ +enum tcptrace_function { + /* send */ + PT_USER, + PT_KERN_RAW_SENDMSG, + //PT_KERN_IP_FIN_OUTPUT, /* not trace now */ + PT_KERN_DEV_QUE_XMIT, + /* recv */ + PT_KERN_NET_RECV_SKB, + PT_KERN_IP_RCV, + PT_KERN_TCP_V4_RCV, + PT_MAX, +}; + +struct tcptrace_map_entry { + uint32_t function_id; + uint32_t padding; + uint64_t ns; +}; + +struct tcptrace_map_value { + struct tcptrace_map_entry entries[TCPTRACE_MAP_ENTRY_NUM]; +}; + +struct tcptrace_map_key { + uint32_t seq; +}; + +#endif //TCPTRACE_DATA_DEFINE_H diff --git a/source/tools/detect/net_diag/tcpping/include/libnet.h b/source/tools/detect/net_diag/tcpping/include/libnet.h new file mode 100644 index 0000000000000000000000000000000000000000..a7fed3cc285642bd6475e5b98d1db03802cdf738 --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/include/libnet.h @@ -0,0 +1,116 @@ +/* + * libnet + * libnet.h - Network routine library header file + * include/libnet.h. Generated from libnet.h.in by configure. + * + * Copyright (c) 1998 - 2004 Mike D. Schiffman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef __LIBNET_H +#define __LIBNET_H + +/** + * @file libnet.h + * @brief Top-level libnet header file + * + * @details This section doesn't contain any details about libnet.h. + * + * For details, see libnet-functions.h and libnet-macros.h + */ + +#ifdef __cplusplus +extern "C" { +#endif + + /* + * TODO move the stuff we ALWAYS need out of the DOXYGEN ifndef block + * and minimize their redundancies (see doc/TODO) + */ +#ifndef DOXYGEN_SHOULD_SKIP_THIS +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#if !defined(_MSC_VER) +#include +#endif + +#if defined(HAVE_SYS_SOCKIO_H) && !defined(SIOCGIFADDR) +#include +#endif + +#if !defined(__WIN32__) +#include +#include +#include +#include +#include +#include +#else /* __WIN32__ */ +#if (__CYGWIN__) +#include +#endif +#include +#include +#include +#include +#endif /* __WIN32__ */ + +#if (HAVE_NET_ETHERNET_H) +#include +#endif /* HAVE_NET_ETHERNET_H */ + +#define LIBNET_VERSION "1.3-dev" + +#define LIBNET_LIL_ENDIAN 1 + +#ifndef LIBNET_API +#define LIBNET_API +#endif +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +#include "./libnet/libnet-types.h" +#include "./libnet/libnet-macros.h" +#include "./libnet/libnet-headers.h" +#include "./libnet/libnet-structures.h" +#include "./libnet/libnet-asn1.h" +#include "./libnet/libnet-functions.h" + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBNET_H */ + diff --git a/source/tools/detect/net_diag/tcpping/include/libnet/Makefile.am b/source/tools/detect/net_diag/tcpping/include/libnet/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..ef43b538e5ac38f1159d40c1334a6c32c080ddc5 --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/include/libnet/Makefile.am @@ -0,0 +1,12 @@ +# $Id: Makefile.am,v 1.2 2003/10/18 17:20:03 mike Exp $ + +include $(top_srcdir)/Makefile.am.common + +libnetincludedir = $(includedir)/libnet + +libnetinclude_HEADERS = libnet-asn1.h \ + libnet-functions.h \ + libnet-headers.h \ + libnet-macros.h \ + libnet-structures.h \ + libnet-types.h diff --git a/source/tools/detect/net_diag/tcpping/include/libnet/libnet-asn1.h b/source/tools/detect/net_diag/tcpping/include/libnet/libnet-asn1.h new file mode 100644 index 0000000000000000000000000000000000000000..06b985ad1b36c5d96c10f0f0e92d6bab00cc41df --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/include/libnet/libnet-asn1.h @@ -0,0 +1,260 @@ +/* + * $Id: libnet-asn1.h,v 1.3 2004/01/17 07:51:19 mike Exp $ + * + * libnet-asn1.h - Network routine library ASN.1 header file + * + * Copyright (c) 1998 - 2004 Mike D. Schiffman + * All rights reserved. + * + * Definitions for Abstract Syntax Notation One, ASN.1 + * As defined in ISO/IS 8824 and ISO/IS 8825 + * + * Copyright 1988, 1989 by Carnegie Mellon University + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of CMU not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Copyright (c) 1998 - 2001 Mike D. Schiffman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __LIBNET_ASN1_H +#define __LIBNET_ASN1_H + +#ifndef EIGHTBIT_SUBIDS +typedef uint32_t oid; +#define MAX_SUBID 0xFFFFFFFF +#else +typedef uint8_t oid; +#define MAX_SUBID 0xFF +#endif + +#define MAX_OID_LEN 64 /* max subid's in an oid */ + +#define ASN_BOOLEAN (0x01) +#define ASN_INTEGER (0x02) +#define ASN_BIT_STR (0x03) +#define ASN_OCTET_STR (0x04) +#define ASN_NULL (0x05) +#define ASN_OBJECT_ID (0x06) +#define ASN_SEQUENCE (0x10) +#define ASN_SET (0x11) + +#define ASN_UNIVERSAL (0x00) +#define ASN_APPLICATION (0x40) +#define ASN_CONTEXT (0x80) +#define ASN_PRIVATE (0xC0) + +#define ASN_PRIMITIVE (0x00) +#define ASN_CONSTRUCTOR (0x20) + +#define ASN_LONG_LEN (0x80) +#define ASN_EXTENSION_ID (0x1F) +#define ASN_BIT8 (0x80) + +#define IS_CONSTRUCTOR(byte) ((byte) & ASN_CONSTRUCTOR) +#define IS_EXTENSION_ID(byte) (((byte) & ASN_EXTENSION_ID) = ASN_EXTENSION_ID) + +/* + * All of the build_asn1_* (build_asn1_length being an exception) functions + * take the same first 3 arguments: + * + * uint8_t *data: This is a pointer to the start of the data object to be + * manipulated. + * int *datalen: This is a pointer to the number of valid bytes following + * "data". This should be not be exceeded in any function. + * Upon exiting a function, this value will reflect the + * changed "data" and then refer to the new number of valid + * bytes until the end of "data". + * uint8_t type: The ASN.1 object type. + */ + + +/* + * Builds an ASN object containing an integer. + * + * Returns NULL upon error or a pointer to the first byte past the end of + * this object (the start of the next object). + */ + +uint8_t * +libnet_build_asn1_int( + uint8_t *, /* Pointer to the output buffer */ + int *, /* Number of valid bytes left in the buffer */ + uint8_t, /* ASN object type */ + int32_t *, /* Pointer to a int32_t integer */ + int /* Size of a int32_t integer */ + ); + + +/* + * Builds an ASN object containing an unsigned integer. + * + * Returns NULL upon error or a pointer to the first byte past the end of + * this object (the start of the next object). + */ + +uint8_t * +libnet_build_asn1_uint( + uint8_t *, /* Pointer to the output buffer */ + int *, /* Number of valid bytes left in the buffer */ + uint8_t, /* ASN object type */ + uint32_t *, /* Pointer to an unsigned int32_t integer */ + int /* Size of a int32_t integer */ + ); + + +/* + * Builds an ASN object containing an octect string. + * + * Returns NULL upon error or a pointer to the first byte past the end of + * this object (the start of the next object). + */ + +uint8_t * +libnet_build_asn1_string( + uint8_t *, /* Pointer to the output buffer */ + int *, /* Number of valid bytes left in the buffer */ + uint8_t, /* ASN object type */ + uint8_t *, /* Pointer to a string to be built into an object */ + int /* Size of the string */ + ); + + +/* + * Builds an ASN header for an object with the ID and length specified. This + * only works on data types < 30, i.e. no extension octets. The maximum + * length is 0xFFFF; + * + * Returns a pointer to the first byte of the contents of this object or + * NULL upon error + */ + +uint8_t * +libnet_build_asn1_header( + uint8_t *, /* Pointer to the start of the object */ + int *, /* Number of valid bytes left in buffer */ + uint8_t, /* ASN object type */ + int /* ASN object length */ + ); + + +uint8_t * +libnet_build_asn1_length( + uint8_t *, /* Pointer to start of object */ + int *, /* Number of valid bytes in buffer */ + int /* Length of object */ + ); + + +/* + * Builds an ASN header for a sequence with the ID and length specified. + * + * This only works on data types < 30, i.e. no extension octets. + * The maximum length is 0xFFFF; + * + * Returns a pointer to the first byte of the contents of this object. + * Returns NULL on any error. + */ + +uint8_t * +libnet_build_asn1_sequence( + uint8_t *, + int *, + uint8_t, + int + ); + + +/* + * Builds an ASN object identifier object containing the input string. + * + * Returns NULL upon error or a pointer to the first byte past the end of + * this object (the start of the next object). + */ + +uint8_t * +libnet_build_asn1_objid( + uint8_t *, + int *, + uint8_t, + oid *, + int + ); + + +/* + * Builds an ASN null object. + * + * Returns NULL upon error or a pointer to the first byte past the end of + * this object (the start of the next object). + */ + +uint8_t * +libnet_build_asn1_null( + uint8_t *, + int *, + uint8_t + ); + + +/* + * Builds an ASN bitstring. + * + * Returns NULL upon error or a pointer to the first byte past the end of + * this object (the start of the next object). + */ + +uint8_t * +libnet_build_asn1_bitstring( + uint8_t *, + int *, + uint8_t, + uint8_t *, /* Pointer to the input buffer */ + int /* Length of the input buffer */ + ); + + +#endif /* __LIBNET_ASN1_H */ + +/** + * Local Variables: + * indent-tabs-mode: nil + * c-file-style: "stroustrup" + * End: + */ diff --git a/source/tools/detect/net_diag/tcpping/include/libnet/libnet-functions.h b/source/tools/detect/net_diag/tcpping/include/libnet/libnet-functions.h new file mode 100644 index 0000000000000000000000000000000000000000..a4e00f5b5b50f360f7b639d09d7ca42bf900999c --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/include/libnet/libnet-functions.h @@ -0,0 +1,2734 @@ +/* + * libnet + * libnet-functions.h - function prototypes + * + * Copyright (c) 1998 - 2004 Mike D. Schiffman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef __LIBNET_FUNCTIONS_H +#define __LIBNET_FUNCTIONS_H +/** + * @file libnet-functions.h + * @brief libnet exported function prototypes + */ + +/** + * Creates the libnet environment. It initializes the library and returns a + * libnet context. If the injection_type is LIBNET_LINK or LIBNET_LINK_ADV, the + * function initializes the injection primitives for the link-layer interface + * enabling the application programmer to build packets starting at the + * data-link layer (which also provides more granular control over the IP + * layer). If libnet uses the link-layer and the device argument is non-NULL, + * the function attempts to use the specified network device for packet + * injection. This is either a canonical string that references the device + * (such as "eth0" for a 100MB Ethernet card on Linux or "fxp0" for a 100MB + * Ethernet card on OpenBSD) or the dots and decimals representation of the + * device's IP address (192.168.0.1). If device is NULL, libnet attempts to + * find a suitable device to use. If the injection_type is LIBNET_RAW4 or + * LIBNET_RAW4_ADV, the function initializes the injection primitives for the + * IPv4 raw socket interface. The final argument, err_buf, should be a buffer + * of size LIBNET_ERRBUF_SIZE and holds an error message if the function fails. + * This function requires root privileges to execute successfully. Upon + * success, the function returns a valid libnet context for use in later + * function calls; upon failure, the function returns NULL. + * @param injection_type packet injection type (LIBNET_LINK, LIBNET_LINK_ADV, LIBNET_RAW4, LIBNET_RAW4_ADV, LIBNET_RAW6, LIBNET_RAW6_ADV) + * @param device the interface to use (NULL and libnet will choose one) + * @param err_buf will contain an error message on failure + * @return libnet context ready for use or NULL on error. + */ +LIBNET_API +libnet_t * +libnet_init(int injection_type, const char *device, char *err_buf); + +/** + * Shuts down the libnet session referenced by l. It closes the network + * interface and frees all internal memory structures associated with l. + * @param l pointer to a libnet context + */ +LIBNET_API +void +libnet_destroy(libnet_t *l); + +/** + * Clears the current packet referenced and frees all pblocks. Should be + * called when the programmer want to send a completely new packet of + * a different type using the same context. + * @param l pointer to a libnet context + */ +LIBNET_API +void +libnet_clear_packet(libnet_t *l); + +/** + * Fills in a libnet_stats structure with packet injection statistics + * (packets written, bytes written, packet sending errors). + * @param l pointer to a libnet context + * @param ls pointer to a libnet statistics structure + */ +LIBNET_API +void +libnet_stats(libnet_t *l, struct libnet_stats *ls); + +/** + * Returns the FILENO of the file descriptor used for packet injection. + * @param l pointer to a libnet context + * @return the file number of the file descriptor used for packet injection + */ +LIBNET_API +int +libnet_getfd(libnet_t *l); + +/** + * Returns the canonical name of the device used for packet injection. + * @param l pointer to a libnet context + * @return the canonical name of the device used for packet injection. Note + * it can be NULL without being an error. + */ +LIBNET_API +const char * +libnet_getdevice(libnet_t *l); + +/** + * Returns the pblock buffer contents for the specified ptag; a + * subsequent call to libnet_getpbuf_size() should be made to determine the + * size of the buffer. + * @param l pointer to a libnet context + * @param ptag the ptag reference number + * @return a pointer to the pblock buffer or NULL on error + */ +LIBNET_API +uint8_t * +libnet_getpbuf(libnet_t *l, libnet_ptag_t ptag); + +/** + * Returns the pblock buffer size for the specified ptag; a + * previous call to libnet_getpbuf() should be made to pull the actual buffer + * contents. + * @param l pointer to a libnet context + * @param ptag the ptag reference number + * @return the size of the pblock buffer + */ +LIBNET_API +uint32_t +libnet_getpbuf_size(libnet_t *l, libnet_ptag_t ptag); + +/** + * Returns the last error set inside of the referenced libnet context. This + * function should be called anytime a function fails or an error condition + * is detected inside of libnet. + * @param l pointer to a libnet context + * @return an error string or NULL if no error has occurred + */ +LIBNET_API +char * +libnet_geterror(libnet_t *l); + +/** + * Returns the sum of the size of all of the pblocks inside of l (this should + * be the resulting packet size). + * @param l pointer to a libnet context + * @return the size of the packet in l + */ +LIBNET_API +uint32_t +libnet_getpacket_size(libnet_t *l); + +/** + * Seeds the pseudo-random number generator. + * @param l pointer to a libnet context + * @retval 1 on success + * @retval -1 on failure + */ +LIBNET_API +int +libnet_seed_prand(libnet_t *l); + +/** + * Generates an unsigned pseudo-random value within the range specified by + * mod. + * LIBNET_PR2 0 - 1 + * LIBNET_PR8 0 - 255 + * LIBNET_PR16 0 - 32767 + * LIBNET_PRu16 0 - 65535 + * LIBNET_PR32 0 - 2147483647 + * LIBNET_PRu32 0 - 4294967295 + * + * @param mod one the of LIBNET_PR* constants + * @retval 1 on success + * @retval -1 on failure + */ +LIBNET_API +uint32_t +libnet_get_prand(int mod); + +/** + * If a given protocol header is built with the checksum field set to "0", by + * default libnet will calculate the header checksum prior to injection. If the + * header is set to any other value, by default libnet will not calculate the + * header checksum. To over-ride this behavior, use libnet_toggle_checksum(). + * Switches auto-checksumming on or off for the specified ptag. If mode is set + * to LIBNET_ON, libnet will mark the specified ptag to calculate a checksum + * for the ptag prior to injection. This assumes that the ptag refers to a + * protocol that has a checksum field. If mode is set to LIBNET_OFF, libnet + * will clear the checksum flag and no checksum will be computed prior to + * injection. This assumes that the programmer will assign a value (zero or + * otherwise) to the checksum field. Often times this is useful if a + * precomputed checksum or some other predefined value is going to be used. + * Note that when libnet is initialized with LIBNET_RAW4, the IPv4 header + * checksum will always be computed by the kernel prior to injection, + * regardless of what the programmer sets. + * @param l pointer to a libnet context + * @param ptag the ptag reference number + * @param mode LIBNET_ON or LIBNET_OFF + * @retval 1 on success + * @retval -1 on failure + */ +LIBNET_API +int +libnet_toggle_checksum(libnet_t *l, libnet_ptag_t ptag, int mode); + +/** + * Takes a network byte ordered IPv4 address and returns a pointer to either a + * canonical DNS name (if it has one) or a string of dotted decimals. This may + * incur a DNS lookup if the hostname and mode is set to LIBNET_RESOLVE. If + * mode is set to LIBNET_DONT_RESOLVE, no DNS lookup will be performed and + * the function will return a pointer to a dotted decimal string. The function + * cannot fail -- if no canonical name exists, it will fall back on returning + * a dotted decimal string. This function is non-reentrant. + * @param in network byte ordered IPv4 address + * @param use_name LIBNET_RESOLVE or LIBNET_DONT_RESOLVE + * @return a pointer to presentation format string + */ +LIBNET_API +char * +libnet_addr2name4(uint32_t in, uint8_t use_name); + +/** + * Takes a dotted decimal string or a canonical DNS name and returns a + * network byte ordered IPv4 address. This may incur a DNS lookup if mode is + * set to LIBNET_RESOLVE and host_name refers to a canonical DNS name. If mode + * is set to LIBNET_DONT_RESOLVE no DNS lookup will occur. The function can + * fail if DNS lookup fails or if mode is set to LIBNET_DONT_RESOLVE and + * host_name refers to a canonical DNS name. + * @param l pointer to a libnet context + * @param host_name pointer to a string containing a presentation format host + * name + * @param use_name LIBNET_RESOLVE or LIBNET_DONT_RESOLVE + * @return address in network byte order + * @retval -1 (2^32 - 1) on error + */ +LIBNET_API +uint32_t +libnet_name2addr4(libnet_t *l, const char *host_name, uint8_t use_name); + +extern const struct libnet_in6_addr in6addr_error; + +/** + * Check a libnet_in6_addr structure for identity with in6addr_error. + * @param addr address to check + * @retval 1 if addr is in6addr_error + * @retval 0 if it is not + */ +LIBNET_API +int +libnet_in6_is_error(struct libnet_in6_addr addr); + +/** + * Takes a dotted decimal string or a canonical DNS name and returns a + * network byte ordered IPv6 address. This may incur a DNS lookup if mode is + * set to LIBNET_RESOLVE and host_name refers to a canonical DNS name. If mode + * is set to LIBNET_DONT_RESOLVE no DNS lookup will occur. The function can + * fail if DNS lookup fails or if mode is set to LIBNET_DONT_RESOLVE and + * host_name refers to a canonical DNS name. + * @param l pointer to a libnet context + * @param host_name pointer to a string containing a presentation format host + * name + * @param use_name LIBNET_RESOLVE or LIBNET_DONT_RESOLVE + * @return network byte ordered IPv6 address structure + */ +LIBNET_API +struct libnet_in6_addr +libnet_name2addr6(libnet_t *l, const char *host_name, uint8_t use_name); + +/** + * Should document this baby right here. + */ +LIBNET_API +void +libnet_addr2name6_r(struct libnet_in6_addr addr, uint8_t use_name, +char *host_name, int host_name_len); + +/** + * Creates a new port list. Port list chains are useful for TCP and UDP-based + * applications that need to send packets to a range of ports (contiguous or + * otherwise). The port list chain, which token_list points to, should contain + * a series of int8_tacters from the following list: "0123456789,-" of the + * general format "x - y, z", where "xyz" are port numbers between 0 and + * 65,535. plist points to the front of the port list chain list for use in + * further libnet_plist_chain() functions. Upon success, the function returns + * 1. Upon failure, the function returns -1 and libnet_geterror() can tell you + * why. + * @param l pointer to a libnet context + * @param plist if successful, will refer to the portlist, if not, NULL + * @param token_list string containing the port list primitive + * @retval 1 on success + * @retval -1 on failure + */ +LIBNET_API +int +libnet_plist_chain_new(libnet_t *l, libnet_plist_t **plist, char *token_list); + +/** + * Returns the next port list chain pair from the port list chain plist. bport + * and eport contain the starting port number and ending port number, + * respectively. Upon success, the function returns 1 and fills in the port + * variables; however, if the list is empty, the function returns 0 and sets + * both port variables to 0. Upon failure, the function returns -1. + * @param plist previously created portlist + * @param bport will contain the beginning port number or 0 + * @param eport will contain the ending port number or 0 + * @retval 1 on success + * @retval 0 if empty + * @retval -1 on failure + */ +LIBNET_API +int +libnet_plist_chain_next_pair(libnet_plist_t *plist, uint16_t *bport, +uint16_t *eport); + +/** + * Runs through the port list and prints the contents of the port list chain + * list to stdout. + * @param plist previously created portlist + * @retval 1 on success + * @retval -1 on failure + */ +LIBNET_API +int +libnet_plist_chain_dump(libnet_plist_t *plist); + +/** + * Runs through the port list and prints the contents of the port list chain + * list to string. This function uses strdup and is not re-entrant. It also + * has a memory leak and should not really be used. + * @param plist previously created portlist + * @return a printable string containing the port list contents on success or NULL on error + */ +LIBNET_API +char * +libnet_plist_chain_dump_string(libnet_plist_t *plist); + +/** + * Frees all memory associated with port list chain. + * @param plist previously created portlist + * @retval 1 on success + * @retval -1 on failure + */ +LIBNET_API +int +libnet_plist_chain_free(libnet_plist_t *plist); + +/** + * @section PBF Packet Builder Functions + * + * The core of libnet is the platform-independent packet-building + * functionality. These functions enable an application programmer to build + * protocol headers (and data) in a simple and consistent manner without having + * to worry (too much) about low-level network odds and ends. Each + * libnet_build() function builds a piece of a packet (generally a protocol + * header). While it is perfectly possible to build an entire, + * ready-to-transmit packet with a single call to a libnet_build() function, + * generally more than one builder-class function call is required to construct + * a full packet. A complete wire-ready packet generally consists of more than + * one piece. + * Every function that builds a protocol header takes a series of arguments + * roughly corresponding to the header values as they appear on the wire. This + * process is intuitive but often makes for functions with huge prototypes and + * large stack frames. + * One important thing to note is that you must call these functions in order, + * corresponding to how they should appear on the wire (from the highest + * protocol layer on down). This building process is intuitive; it approximates + * what happens in an operating system kernel. In other words, to build a + * Network Time Protocol (NTP) packet by using the link-layer interface, the + * application programmer would call the libnet_build() functions in the + * following order: + * 1. libnet_build_ntp() + * 2. libnet_build_udp() + * 3. libnet_build_ipv4() + * 4. libnet_build_ethernet() + * This ordering is essential for libnet 1.1.x to properly link together the + * packet internally (previous libnet versions did not have the requirement). + * + * @subsection TPI The Payload Interface + * + * The payload interface specifies an optional way to include data directly + * after the protocol header in question. You can use this function for a + * variety of purposes, including the following: + * - Including additional or arbitrary protocol header information that is not + * available from a libnet interface + * - Including a packet payload (data segment) + * - Building another protocol header that is not available from a libnet + * interface + * To employ the interface, the application programmer should construct the i + * payload data and pass a const uint8_t * to this data and its size to the desired + * libnet_build() function. Libnet handles the rest. + * + * It is important to note that some functions (notably the IPv6 builders) do + * use the payload interface to specify variable length but ostensibly + * non-optional data. See the individual libnet_build_ipv6*() functions for + * more information. + * + * @subsection PT Protocol Tags and Packet Builder Return Values + * + * Libnet uses the protocol tag (ptag) to identify individual pieces of a + * packet after being created. A new ptag results every time a libnet_build() + * function with an empty (0) ptag argument completes successfully. This new + * ptag now refers to the packet piece just created. The application + * programmer's responsibility is to save this value if he or she plans to + * modify this particular portion later on in the program. If the application + * programmer needs to modify some portion of that particular packet piece + * again, he or she calls the same libnet_build() function specifying the + * saved ptag argument. Libnet then searches for that packet piece and modifies + * it rather than creating a new one. Upon failure for any reason, + * libnet_build() functions return -1; libnet_geterror() tells you why. + */ + +/** + * Builds an IEEE 802.1q VLAN tagging header. Depending on the value of + * len_proto, the function wraps the 802.1q header inside either an IEEE 802.3 + * header or an RFC 894 Ethernet II (DIX) header (both resulting in an 18-byte + * frame). If len is 1500 or less, most receiving protocol stacks parse the + * frame as an IEEE 802.3 encapsulated frame. If len is one of the Ethernet type + * values, most protocol stacks parse the frame as an RFC 894 Ethernet II + * encapsulated frame. Note the length value is calculated without the 802.1q + * header of 18 bytes. + * @param dst pointer to a six byte source ethernet address + * @param src pointer to a six byte destination ethernet address + * @param tpi tag protocol identifier + * @param priority priority + * @param cfi canonical format indicator + * @param vlan_id vlan identifier + * @param len_proto length (802.3) protocol (Ethernet II) + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_802_1q(const uint8_t *dst, const uint8_t *src, uint16_t tpi, +uint8_t priority, uint8_t cfi, uint16_t vlan_id, uint16_t len_proto, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an IEEE 802.1x extended authentication protocol header. + * @param eap_ver the EAP version + * @param eap_type the EAP type + * @param length frame length + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_802_1x(uint8_t eap_ver, uint8_t eap_type, uint16_t length, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an IEEE 802.2 LLC header. + * @param dsap destination service access point + * @param ssap source service access point + * @param control control field + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_802_2(uint8_t dsap, uint8_t ssap, uint8_t control, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an IEEE 802.2 LLC SNAP header. + * @param dsap destination service access point + * @param ssap source service access point + * @param control control field + * @param oui Organizationally Unique Identifier + * @param type upper layer protocol + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_802_2snap(uint8_t dsap, uint8_t ssap, uint8_t control, +uint8_t *oui, uint16_t type, const uint8_t* payload, uint32_t payload_s, +libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an IEEE 802.3 header. The 802.3 header is almost identical to the + * RFC 894 Ethernet II header, the exception being that the field immediately + * following the source address holds the frame's length (as opposed to the + * layer 3 protocol). You should only use this function when libnet is + * initialized with the LIBNET_LINK interface. + * @param dst destination ethernet address + * @param src source ethernet address + * @param len frame length sans header + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_802_3(const uint8_t *dst, const uint8_t *src, uint16_t len, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an Ethernet header. The RFC 894 Ethernet II header is almost + * identical to the IEEE 802.3 header, with the exception that the field + * immediately following the source address holds the layer 3 protocol (as + * opposed to frame's length). You should only use this function when + * libnet is initialized with the LIBNET_LINK interface. + * @param dst destination ethernet address + * @param src source ethernet address + * @param type upper layer protocol type + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ethernet(const uint8_t *dst, const uint8_t *src, uint16_t type, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Autobuilds an Ethernet header. The RFC 894 Ethernet II header is almost + * identical to the IEEE 802.3 header, with the exception that the field + * immediately following the source address holds the layer 3 protocol (as + * opposed to frame's length). You should only use this function when + * libnet is initialized with the LIBNET_LINK interface. + * @param dst destination ethernet address + * @param type upper layer protocol type + * @param l pointer to a libnet context + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_autobuild_ethernet(const uint8_t *dst, uint16_t type, libnet_t *l); + +/** + * Builds a Fiber Distributed Data Interface (FDDI) header. + * @param fc class format and priority + * @param dst destination fddi address + * @param src source fddi address + * @param dsap destination service access point + * @param ssap source service access point + * @param cf cf + * @param oui 3 byte IEEE organizational code + * @param type upper layer protocol + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_fddi(uint8_t fc, const uint8_t *dst, const uint8_t *src, uint8_t dsap, +uint8_t ssap, uint8_t cf, const uint8_t *oui, uint16_t type, const uint8_t* payload, +uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Autobuilds a Fiber Distributed Data Interface (FDDI) header. + * @param fc class format and priority + * @param dst destination fddi address + * @param dsap destination service access point + * @param ssap source service access point + * @param cf cf + * @param oui IEEE organizational code + * @param type upper layer protocol + * @param l pointer to a libnet context + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_autobuild_fddi(uint8_t fc, const uint8_t *dst, uint8_t dsap, uint8_t ssap, +uint8_t cf, const uint8_t *oui, uint16_t type, libnet_t *l); + +/** + * Builds an Address Resolution Protocol (ARP) header. Depending on the op + * value, the function builds one of several different types of RFC 826 or + * RFC 903 RARP packets. + * @param hrd hardware address format + * @param pro protocol address format + * @param hln hardware address length + * @param pln protocol address length + * @param op ARP operation type + * @param sha sender's hardware address + * @param spa sender's protocol address + * @param tha target hardware address + * @param tpa target protocol address + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_arp(uint16_t hrd, uint16_t pro, uint8_t hln, uint8_t pln, +uint16_t op, const uint8_t *sha, const uint8_t *spa, const uint8_t *tha, const uint8_t *tpa, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Autouilds an Address Resolution Protocol (ARP) header. Depending on the op + * value, the function builds one of several different types of RFC 826 or + * RFC 903 RARP packets. + * @param op ARP operation type + * @param sha sender's hardware address + * @param spa sender's protocol address + * @param tha target hardware address + * @param tpa target protocol address + * @param l pointer to a libnet context + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_autobuild_arp(uint16_t op, const uint8_t *sha, const uint8_t *spa, const uint8_t *tha, +const uint8_t *tpa, libnet_t *l); + +/** + * Builds an RFC 793 Transmission Control Protocol (TCP) header. + * @param sp source port + * @param dp destination port + * @param seq sequence number + * @param ack acknowledgement number + * @param control control flags + * @param win window size + * @param sum checksum (0 for libnet to auto-fill) + * @param urg urgent pointer + * @param len total length of the TCP packet (for checksum calculation) + * @param payload + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_tcp(uint16_t sp, uint16_t dp, uint32_t seq, uint32_t ack, +uint8_t control, uint16_t win, uint16_t sum, uint16_t urg, uint16_t len, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an RFC 793 Transmission Control Protocol (TCP) options header. + * The function expects options to be a valid TCP options string of size + * options_s, which is no larger than 40 bytes (the maximum size of an + * options string). The function checks to ensure that the packet consists of + * a TCP header preceded by an IPv4 header, and that the addition of the + * options string would not result in a packet larger than 65,535 bytes + * (IPMAXPACKET). The function counts up the number of 32-bit words in the + * options string and adjusts the TCP header length value as necessary. + * @param options byte string of TCP options + * @param options_s length of options string + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_tcp_options(const uint8_t *options, uint32_t options_s, libnet_t *l, +libnet_ptag_t ptag); + +/** + * Builds an RFC 768 User Datagram Protocol (UDP) header. + * @param sp source port + * @param dp destination port + * @param len total length of the UDP packet + * @param sum checksum (0 for libnet to auto-fill) + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_udp(uint16_t sp, uint16_t dp, uint16_t len, uint16_t sum, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds a Cisco Discovery Protocol (CDP) header. Cisco Systems designed CDP + * to aid in the network management of adjacent Cisco devices. The CDP protocol + * specifies data by using a type/length/value (TLV) setup. The first TLV can + * specified by using the functions type, length, and value arguments. To + * specify additional TLVs, the programmer could either use the payload + * interface or libnet_build_data() to construct them. + * @param version CDP version + * @param ttl time to live (time information should be cached by recipient) + * @param sum checksum (0 for libnet to auto-fill) + * @param type type of data contained in value + * @param value_s length of value argument + * @param value the CDP information string + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_cdp(uint8_t version, uint8_t ttl, uint16_t sum, uint16_t type, +uint16_t value_s, const uint8_t *value, const uint8_t* payload, uint32_t payload_s, +libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds a LLDP Chassis ID TLV. The Chassis ID TLV is the _first_ mandatory TLV in the LLDPDU. + * @param subtype Chassis ID Subtype + * @param value the Chassis ID string + * @param value_s length of value argument + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t libnet_build_lldp_chassis(const uint8_t subtype, +const uint8_t *value, const uint8_t value_s, +libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds a LLDP Port ID TLV. The Port ID TLV is the _second_ mandatory TLV in the LLDPDU. + * @param subtype Port ID Subtype + * @param value the Port ID string + * @param value_s length of value argument + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t libnet_build_lldp_port(const uint8_t subtype, +const uint8_t *value, const uint8_t value_s, +libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds a LLDP TTL TLV. The TTL TLV is the _third_ mandatory TLV in the LLDPDU. + * @param ttl number of seconds + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t libnet_build_lldp_ttl(const uint16_t ttl, +libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds a LLDP End of LLDPDU TLV. + * The End of LLDPDU TLV used to mark the end of the TLV sequence in LLDPDU. + * Is a 2 octet all-zero TLV + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t libnet_build_lldp_end(libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds a LLDP Organization Specific TLV. + * @param value the TLV information string + * @param value_s length of value argument + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t libnet_build_lldp_org_spec(const uint8_t *value, +const uint16_t value_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * At the moment, this function is not implemented. + * This stub may be useful in feature to let to the user + * to build the LLDPDU in one function by passing corresponding + * arguments. + */ +LIBNET_API +libnet_ptag_t libnet_build_lldp(libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an IP version 4 RFC 792 Internet Control Message Protocol (ICMP) + * echo request/reply header + * @param type type of ICMP packet (should be ICMP_ECHOREPLY or ICMP_ECHO) + * @param code code of ICMP packet (should be 0) + * @param sum checksum (0 for libnet to auto-fill) + * @param id identification number + * @param seq packet sequence number + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_icmpv4_echo(uint8_t type, uint8_t code, uint16_t sum, +uint16_t id, uint16_t seq, const uint8_t* payload, uint32_t payload_s, +libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an IP version 4 RFC 792 Internet Control Message Protocol (ICMP) + * IP netmask request/reply header. + * @param type type of ICMP packet (should be ICMP_MASKREQ or ICMP_MASKREPLY) + * @param code code of ICMP packet (should be 0) + * @param sum checksum (0 for libnet to auto-fill) + * @param id identification number + * @param seq packet sequence number + * @param mask subnet mask + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_icmpv4_mask(uint8_t type, uint8_t code, uint16_t sum, +uint16_t id, uint16_t seq, uint32_t mask, const uint8_t* payload, +uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an IP version 4 RFC 792 Internet Control Message Protocol (ICMP) + * unreachable header. The IP header that caused the error message should be + * built by a previous call to libnet_build_ipv4(). + * @param type type of ICMP packet (should be ICMP_UNREACH) + * @param code code of ICMP packet (should be one of the 16 unreachable codes) + * @param sum checksum (0 for libnet to auto-fill) + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_icmpv4_unreach(uint8_t type, uint8_t code, uint16_t sum, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an IP version 4 RFC 792 Internet Message Control Protocol (ICMP) + * redirect header. The IP header that caused the error message should be + * built by a previous call to libnet_build_ipv4(). + * @param type type of ICMP packet (should be ICMP_REDIRECT) + * @param code code of ICMP packet (should be one of the four redirect codes) + * @param sum checksum (0 for libnet to auto-fill) + * @param gateway + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_icmpv4_redirect(uint8_t type, uint8_t code, uint16_t sum, +uint32_t gateway, const uint8_t* payload, uint32_t payload_s, libnet_t *l, +libnet_ptag_t ptag); + +/** + * Builds an IP version 4 RFC 792 Internet Control Message Protocol (ICMP) time + * exceeded header. The IP header that caused the error message should be + * built by a previous call to libnet_build_ipv4(). + * @param type type of ICMP packet (should be ICMP_TIMXCEED) + * @param code code of ICMP packet (ICMP_TIMXCEED_INTRANS / ICMP_TIMXCEED_REASS) + * @param sum checksum (0 for libnet to auto-fill) + * @param payload optional payload or NULL + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_icmpv4_timeexceed(uint8_t type, uint8_t code, uint16_t sum, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an IP version 4 RFC 792 Internet Control Message Protocol (ICMP) + * timestamp request/reply header. + * @param type type of ICMP packet (should be ICMP_TSTAMP or ICMP_TSTAMPREPLY) + * @param code code of ICMP packet (should be 0) + * @param sum checksum (0 for libnet to auto-fill) + * @param id identification number + * @param seq sequence number + * @param otime originate timestamp + * @param rtime receive timestamp + * @param ttime transmit timestamp + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_icmpv4_timestamp(uint8_t type, uint8_t code, uint16_t sum, +uint16_t id, uint16_t seq, uint32_t otime, uint32_t rtime, uint32_t ttime, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an IP version 6 RFC 4443 Internet Control Message Protocol (ICMP) + * echo or echo reply header. + * @param type type of ICMP packet (should be ICMP6_ECHO_REQUEST or ICMP6_ECHO_REPLY) + * @param code code of ICMP packet (should be zero) + * @param sum checksum (0 for libnet to auto-fill) + * @param id echo id number + * @param seq echo sequence number + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t libnet_build_icmpv6_echo(uint8_t type, uint8_t code, uint16_t + sum, uint16_t id, uint16_t seq, uint8_t *payload, uint32_t payload_s, + libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an IP version 6 RFC 4443 Internet Control Message Protocol (ICMP) + * unreachable header. The IP header that caused the error message should be + * built by a previous call to libnet_build_ipv6(). + * @param type type of ICMP packet (should be ICMP6_DST_UNREACH) + * @param code code of ICMP packet (should be one of the 5 ICMP6_DST_UNREACH_* codes) + * @param sum checksum (0 for libnet to auto-fill) + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_icmpv6_unreach(uint8_t type, uint8_t code, uint16_t sum, +uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an IP version 6 RFC 2461 Internet Control Message Protocol (ICMP) + * NDP neighbour solicitation header. Could be used with + * libnet_build_icmpv6_ndp_opt() and ICMPV6_NDP_OPT_SLLA. + * @param type type of ICMP packet (should be ND_NEIGHBOR_SOLICIT) + * @param code code of ICMP packet (should be zero) + * @param sum checksum (0 for libnet to auto-fill) + * @param target target ipv6 address + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t libnet_build_icmpv6_ndp_nsol(uint8_t type, uint8_t code, + uint16_t sum, struct libnet_in6_addr target, uint8_t *payload, uint32_t + payload_s, libnet_t* l, libnet_ptag_t ptag); + +/** + * Builds an IP version 6 RFC 2461 Internet Control Message Protocol (ICMP) + * NDP neighbour advertisement header. Could be used with + * libnet_build_icmpv6_ndp_opt() and ND_OPT_TARGET_LINKADDR. + * @param type type of ICMP packet (should be ND_NEIGHBOR_ADVERT) + * @param code code of ICMP packet (should be zero) + * @param sum checksum (0 for libnet to auto-fill) + * @param flags should be a bitwise or of any applicable ND_NA_FLAG_* flags + * @param target target ipv6 address + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t libnet_build_icmpv6_ndp_nadv(uint8_t type, uint8_t code, + uint16_t sum, uint32_t flags, struct libnet_in6_addr target, uint8_t + *payload, uint32_t payload_s, libnet_t* l, libnet_ptag_t ptag); + +/** + * Builds ICMPv6 NDP options. + * @param type one of ND_OPT_* types + * @param option option data + * @param option_s size of option data (will be padded out to an 8-byte boundary) + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t libnet_build_icmpv6_ndp_opt(uint8_t type, uint8_t* option, + uint32_t option_s, libnet_t* l, libnet_ptag_t ptag); + +/** + * Builds an RFC 1112 Internet Group Membership Protocol (IGMP) header. + * @param type packet type + * @param reserved (should be 0 for IGMPv1) + * @param sum checksum (0 for libnet to auto-fill) + * @param ip IPv4 address (in standard/network byte order) + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + * + * @note 'reserved' was previously called 'code', which it is not, in any IGMP version. + */ +LIBNET_API +libnet_ptag_t +libnet_build_igmp(uint8_t type, uint8_t reserved, uint16_t sum, uint32_t ip, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds a version 4 RFC 791 Internet Protocol (IP) header. + * + * @param ip_len total length of the IP packet including all subsequent data (subsequent + * data includes any IP options and IP options padding) + * @param tos type of service bits + * @param id IP identification number + * @param frag fragmentation bits and offset + * @param ttl time to live in the network + * @param prot upper layer protocol + * @param sum checksum (0 for libnet to auto-fill) + * @param src source IPv4 address (little endian) + * @param dst destination IPv4 address (little endian) + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ipv4(uint16_t ip_len, uint8_t tos, uint16_t id, uint16_t frag, +uint8_t ttl, uint8_t prot, uint16_t sum, uint32_t src, uint32_t dst, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an version 4 Internet Protocol (IP) options header. The function + * expects options to be a valid IP options string of size options_s, no larger + * than 40 bytes (the maximum size of an options string). + * + * When building a chain, the options must be built, then the IPv4 header. + * + * When updating a chain, if the block following the options is an IPv4 header, + * it's total length and header length will be updated if the options block + * size changes. + * + * @param options byte string of IP options (it will be padded up to be an integral + * multiple of 32-bit words). + * @param options_s length of options string + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ipv4_options(const uint8_t *options, uint32_t options_s, libnet_t *l, +libnet_ptag_t ptag); + +/** + * Autobuilds a version 4 Internet Protocol (IP) header. The function is useful + * to build an IP header quickly when you do not need a granular level of + * control. The function takes the same len, prot, and dst arguments as + * libnet_build_ipv4(). The function does not accept a ptag argument, but it + * does return a ptag. In other words, you can use it to build a new IP header + * but not to modify an existing one. + * @param len total length of the IP packet including all subsequent data + * @param prot upper layer protocol + * @param dst destination IPv4 address (little endian) + * @param l pointer to a libnet context + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_autobuild_ipv4(uint16_t len, uint8_t prot, uint32_t dst, libnet_t *l); + +/** + * Builds a version 6 RFC 2460 Internet Protocol (IP) header. + * @param tc traffic class + * @param fl flow label + * @param len total length of the IP packet + * @param nh next header + * @param hl hop limit + * @param src source IPv6 address + * @param dst destination IPv6 address + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ipv6(uint8_t tc, uint32_t fl, uint16_t len, uint8_t nh, +uint8_t hl, struct libnet_in6_addr src, struct libnet_in6_addr dst, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds a version 6 RFC 2460 Internet Protocol (IP) fragmentation header. + * @param nh next header + * @param reserved unused value... OR IS IT! + * @param frag fragmentation bits (ala ipv4) + * @param id packet identification + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ipv6_frag(uint8_t nh, uint8_t reserved, uint16_t frag, +uint32_t id, const uint8_t* payload, uint32_t payload_s, libnet_t *l, +libnet_ptag_t ptag); + +/** + * Builds a version 6 RFC 2460 Internet Protocol (IP) routing header. This + * function is special in that it uses the payload interface to include the + * "type-specific data"; that is the routing information. Most often this will + * be a number of 128-bit IPv6 addresses. The application programmer will build + * a byte string of IPv6 address and pass them to the function using the + * payload interface. + * @param nh next header + * @param len length of the header in 8-byte octets not including the first 8 octets + * @param rtype routing header type + * @param segments number of routing segments that follow + * @param payload optional payload of routing information + * @param payload_s payload length + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ipv6_routing(uint8_t nh, uint8_t len, uint8_t rtype, +uint8_t segments, const uint8_t* payload, uint32_t payload_s, libnet_t *l, +libnet_ptag_t ptag); + +/** + * Builds a version 6 RFC 2460 Internet Protocol (IP) destination options + * header. This function is special in that it uses the payload interface to + * include the options data. The application programmer will build an IPv6 + * options byte string and pass it to the function using the payload interface. + * @param nh next header + * @param len length of the header in 8-byte octets not including the first 8 octets + * @param payload options payload + * @param payload_s payload length + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ipv6_destopts(uint8_t nh, uint8_t len, const uint8_t* payload, +uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds a version 6 RFC 2460 Internet Protocol (IP) hop by hop options + * header. This function is special in that it uses the payload interface to + * include the options data. The application programmer will build an IPv6 + * hop by hop options byte string and pass it to the function using the payload + * interface. + * @param nh next header + * @param len length of the header in 8-byte octets not including the first 8 octets + * @param payload options payload + * @param payload_s payload length + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ipv6_hbhopts(uint8_t nh, uint8_t len, const uint8_t* payload, +uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Autobuilds a version 6 RFC 2460 Internet Protocol (IP) header. The function + * is useful to build an IP header quickly when you do not need a granular + * level of control. The function takes the same len, nh, and dst arguments + * as libnet_build_ipv4(). The function does not accept a ptag argument, but it + * does return a ptag. In other words, you can use it to build a new IP header + * but not to modify an existing one. + * This function requires libnet_get_ipaddr6(), which is not yet implemented + * for Win32 platforms. + * @param len length + * @param nh next header + * @param dst destination IPv6 address + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_autobuild_ipv6(uint16_t len, uint8_t nh, struct libnet_in6_addr dst, +libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds a Cisco Inter-Switch Link (ISL) header. + * @param dhost destination address (should be 01:00:0c:00:00) + * @param type type of frame + * @param user user defined data + * @param shost source mac address + * @param len total length of the encapsulated packet less 18 bytes + * @param snap SNAP information (0xaaaa03 + vendor code) + * @param vid 15 bit VLAN ID, 1 bit BPDU or CDP indicator + * @param portindex port index + * @param reserved used for FDDI and token ring + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_isl(uint8_t *dhost, uint8_t type, uint8_t user, +uint8_t *shost, uint16_t len, const uint8_t *snap, uint16_t vid, +uint16_t portindex, uint16_t reserved, const uint8_t* payload, +uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an Internet Protocol Security Encapsulating Security Payload header. + * @param spi security parameter index + * @param seq ESP sequence number + * @param iv initialization vector + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ipsec_esp_hdr(uint32_t spi, uint32_t seq, uint32_t iv, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an Internet Protocol Security Encapsulating Security Payload footer. + * @param len padding length + * @param nh next header + * @param auth authentication data + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ipsec_esp_ftr(uint8_t len, uint8_t nh, int8_t *auth, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an Internet Protocol Security Authentication header. + * @param nh next header + * @param len payload length + * @param res reserved + * @param spi security parameter index + * @param seq sequence number + * @param auth authentication data + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ipsec_ah(uint8_t nh, uint8_t len, uint16_t res, +uint32_t spi, uint32_t seq, uint32_t auth, const uint8_t* payload, +uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an RFC 1035 version 4 DNS header. Additional DNS payload information + * should be specified using the payload interface. + * @param h_len + * @param id DNS packet id + * @param flags control flags + * @param num_q number of questions + * @param num_anws_rr number of answer resource records + * @param num_auth_rr number of authority resource records + * @param num_addi_rr number of additional resource records + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_dnsv4(uint16_t h_len, uint16_t id, uint16_t flags, +uint16_t num_q, uint16_t num_anws_rr, uint16_t num_auth_rr, +uint16_t num_addi_rr, const uint8_t* payload, uint32_t payload_s, libnet_t *l, +libnet_ptag_t ptag); + +/** + * Builds a Routing Information Protocol header (RFCs 1058 and 2453). + * @param cmd command + * @param version protocol version + * @param rd version one: 0, version two: routing domain + * @param af address family + * @param rt version one: 0, version two: route tag + * @param addr IPv4 address + * @param mask version one: 0, version two: subnet mask + * @param next_hop version one: 0, version two: next hop address + * @param metric routing metric + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_rip(uint8_t cmd, uint8_t version, uint16_t rd, uint16_t af, +uint16_t rt, uint32_t addr, uint32_t mask, uint32_t next_hop, +uint32_t metric, const uint8_t* payload, uint32_t payload_s, libnet_t *l, +libnet_ptag_t ptag); + +/** + * Builds an Remote Procedure Call (Version 2) Call message header as + * specified in RFC 1831. This builder provides the option for + * specifying the record marking which is required when used with + * streaming protocols (TCP). + * @param rm record marking indicating the position in a stream, 0 otherwise + * @param xid transaction identifier used to link calls and replies + * @param prog_num remote program specification typically between 0 - 1fffffff + * @param prog_vers remote program version specification + * @param procedure procedure to be performed by remote program + * @param cflavor authentication credential type + * @param clength credential length (should be 0) + * @param cdata opaque credential data (currently unused) + * @param vflavor authentication verifier type + * @param vlength verifier length (should be 0) + * @param vdata opaque verifier data (currently unused) + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_rpc_call(uint32_t rm, uint32_t xid, uint32_t prog_num, +uint32_t prog_vers, uint32_t procedure, uint32_t cflavor, uint32_t clength, +uint8_t *cdata, uint32_t vflavor, uint32_t vlength, const uint8_t *vdata, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an IEEE 802.1d Spanning Tree Protocol (STP) configuration header. + * STP frames are usually encapsulated inside of an 802.2 + 802.3 frame + * combination. + * @param id protocol id + * @param version protocol version + * @param bpdu_type bridge protocol data unit type + * @param flags flags + * @param root_id root id + * @param root_pc root path cost + * @param bridge_id bridge id + * @param port_id port id + * @param message_age message age + * @param max_age max age + * @param hello_time hello time + * @param f_delay forward delay + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_stp_conf(uint16_t id, uint8_t version, uint8_t bpdu_type, +uint8_t flags, const uint8_t *root_id, uint32_t root_pc, const uint8_t *bridge_id, +uint16_t port_id, uint16_t message_age, uint16_t max_age, +uint16_t hello_time, uint16_t f_delay, const uint8_t* payload, +uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an IEEE 802.1d Spanning Tree Protocol (STP) topology change + * notification header. STP frames are usually encapsulated inside of an + * 802.2 + 802.3 frame combination. + * @param id protocol id + * @param version protocol version + * @param bpdu_type bridge protocol data unit type + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_stp_tcn(uint16_t id, uint8_t version, uint8_t bpdu_type, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds a token ring header. + * @param ac access control + * @param fc frame control + * @param dst destination address + * @param src source address + * @param dsap destination service access point + * @param ssap source service access point + * @param cf control field + * @param oui Organizationally Unique Identifier + * @param type upper layer protocol type + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_token_ring(uint8_t ac, uint8_t fc, const uint8_t *dst, const uint8_t *src, +uint8_t dsap, uint8_t ssap, uint8_t cf, const uint8_t *oui, uint16_t type, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Auto-builds a token ring header. + * @param ac access control + * @param fc frame control + * @param dst destination address + * @param dsap destination service access point + * @param ssap source service access point + * @param cf control field + * @param oui Organizationally Unique Identifier + * @param type upper layer protocol type + * @param l pointer to a libnet context + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_autobuild_token_ring(uint8_t ac, uint8_t fc, const uint8_t *dst, +uint8_t dsap, uint8_t ssap, uint8_t cf, const uint8_t *oui, uint16_t type, +libnet_t *l); + +/** + * Builds an RFC 2338 Virtual Router Redundacy Protool (VRRP) header. Use the + * payload interface to specify address and authentication information. To + * build a "legal" packet, the destination IPv4 address should be the multicast * address 224.0.0.18, the IP TTL should be set to 255, and the IP protocol + * should be set to 112. + * @param version VRRP version (should be 2) + * @param type VRRP packet type (should be 1 -- ADVERTISEMENT) + * @param vrouter_id virtual router identification + * @param priority priority (higher numbers indicate higher priority) + * @param ip_count number of IPv4 addresses contained in this advertisement + * @param auth_type type of authentication (0, 1, 2 -- see RFC) + * @param advert_int interval between advertisements + * @param sum checksum (0 for libnet to autofill) + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_vrrp(uint8_t version, uint8_t type, uint8_t vrouter_id, +uint8_t priority, uint8_t ip_count, uint8_t auth_type, uint8_t advert_int, +uint16_t sum, const uint8_t* payload, uint32_t payload_s, libnet_t *l, +libnet_ptag_t ptag); + +/** + * Builds an RFC 3032 Multi-Protocol Label Switching (MPLS) header. + * @param label 20-bit label value + * @param experimental 3-bit reserved field + * @param bos 1-bit bottom of stack identifier + * @param ttl time to live + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_mpls(uint32_t label, uint8_t experimental, uint8_t bos, +uint8_t ttl, const uint8_t* payload, uint32_t payload_s, libnet_t *l, +libnet_ptag_t ptag); + +/** + * Builds an RFC 958 Network Time Protocol (NTP) header. + * @param leap_indicator the leap indicator + * @param version NTP protocol version + * @param mode NTP mode + * @param stratum stratum + * @param poll polling interval + * @param precision precision + * @param delay_int delay interval + * @param delay_frac delay fraction + * @param dispersion_int dispersion interval + * @param dispersion_frac dispersion fraction + * @param reference_id reference id + * @param ref_ts_int reference timestamp integer + * @param ref_ts_frac reference timestamp fraction + * @param orig_ts_int original timestamp integer + * @param orig_ts_frac original timestamp fraction + * @param rec_ts_int receiver timestamp integer + * @param rec_ts_frac receiver timestamp fraction + * @param xmt_ts_int transmit timestamp integer + * @param xmt_ts_frac transmit timestamp integer + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ntp(uint8_t leap_indicator, uint8_t version, uint8_t mode, +uint8_t stratum, uint8_t poll, uint8_t precision, uint16_t delay_int, +uint16_t delay_frac, uint16_t dispersion_int, uint16_t dispersion_frac, +uint32_t reference_id, uint32_t ref_ts_int, uint32_t ref_ts_frac, +uint32_t orig_ts_int, uint32_t orig_ts_frac, uint32_t rec_ts_int, +uint32_t rec_ts_frac, uint32_t xmt_ts_int, uint32_t xmt_ts_frac, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * @param len + * @param type + * @param rtr_id + * @param area_id + * @param sum + * @param autype + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ospfv2(uint16_t len, uint8_t type, uint32_t rtr_id, +uint32_t area_id, uint16_t sum, uint16_t autype, const uint8_t* payload, +uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * @param netmask + * @param interval + * @param opts + * @param priority + * @param dead_int + * @param des_rtr + * @param bkup_rtr + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ospfv2_hello(uint32_t netmask, uint16_t interval, uint8_t opts, +uint8_t priority, uint32_t dead_int, uint32_t des_rtr, uint32_t bkup_rtr, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * @param netmask + * @param interval + * @param opts + * @param priority + * @param dead_int + * @param des_rtr + * @param bkup_rtr + * @param neighbor + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +libnet_ptag_t +libnet_build_ospfv2_hello_neighbor(uint32_t netmask, uint16_t interval, uint8_t opts, +uint8_t priority, uint32_t dead_int, uint32_t des_rtr, uint32_t bkup_rtr, uint32_t neighbor, +const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * @param dgram_len + * @param opts + * @param type + * @param seqnum + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ospfv2_dbd(uint16_t dgram_len, uint8_t opts, uint8_t type, +uint32_t seqnum, const uint8_t* payload, uint32_t payload_s, libnet_t *l, +libnet_ptag_t ptag); + +/** + * @param type + * @param lsid + * @param advrtr + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ospfv2_lsr(uint32_t type, uint32_t lsid, uint32_t advrtr, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * @param num + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ospfv2_lsu(uint32_t num, const uint8_t* payload, uint32_t payload_s, +libnet_t *l, libnet_ptag_t ptag); + +/** + * @param age + * @param opts + * @param type + * @param lsid + * @param advrtr + * @param seqnum + * @param sum + * @param len + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ospfv2_lsa(uint16_t age, uint8_t opts, uint8_t type, +uint32_t lsid, uint32_t advrtr, uint32_t seqnum, uint16_t sum, uint16_t len, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * @param flags + * @param num + * @param id + * @param data + * @param type + * @param tos + * @param metric + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ospfv2_lsa_rtr(uint16_t flags, uint16_t num, uint32_t id, +uint32_t data, uint8_t type, uint8_t tos, uint16_t metric, const uint8_t* payload, +uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * @param nmask + * @param rtrid + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ospfv2_lsa_net(uint32_t nmask, uint32_t rtrid, const uint8_t* payload, +uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * @param nmask + * @param metric + * @param tos + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ospfv2_lsa_sum(uint32_t nmask, uint32_t metric, uint32_t tos, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * @param nmask + * @param metric + * @param fwdaddr + * @param tag + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_ospfv2_lsa_as(uint32_t nmask, uint32_t metric, uint32_t fwdaddr, +uint32_t tag, const uint8_t* payload, uint32_t payload_s, libnet_t *l, +libnet_ptag_t ptag); + +/** + * Builds a generic libnet protocol header. This is useful for including an + * optional payload to a packet that might need to change repeatedly inside + * of a loop. This won't work for TCP or IP payload, they have special types + * (this is probably a bug). + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_data(const uint8_t* payload, uint32_t payload_s, libnet_t *l, +libnet_ptag_t ptag); + +/** + * @param opcode + * @param htype + * @param hlen + * @param hopcount + * @param xid + * @param secs + * @param flags + * @param cip + * @param yip + * @param sip + * @param gip + * @param chaddr client hardware address, length is hlen + * @param sname server host name, a null terminated string + * @param file boot file name, a null terminated string + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_dhcpv4(uint8_t opcode, uint8_t htype, uint8_t hlen, +uint8_t hopcount, uint32_t xid, uint16_t secs, uint16_t flags, +uint32_t cip, uint32_t yip, uint32_t sip, uint32_t gip, const uint8_t *chaddr, +const char *sname, const char *file, const uint8_t* payload, uint32_t payload_s, +libnet_t *l, libnet_ptag_t ptag); + +/** + * @param opcode + * @param htype + * @param hlen + * @param hopcount + * @param xid + * @param secs + * @param flags + * @param cip + * @param yip + * @param sip + * @param gip + * @param chaddr client hardware address, length is hlen + * @param sname server host name, a null terminated string + * @param file boot file name, a null terminated string + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_bootpv4(uint8_t opcode, uint8_t htype, uint8_t hlen, +uint8_t hopcount, uint32_t xid, uint16_t secs, uint16_t flags, +uint32_t cip, uint32_t yip, uint32_t sip, uint32_t gip, const uint8_t *chaddr, +const char *sname, const char *file, const uint8_t* payload, uint32_t payload_s, +libnet_t *l, libnet_ptag_t ptag); + +/** + * @param fv see libnet_build_gre(). + * @return size + * @see libnet_build_gre(). + */ +LIBNET_API +uint32_t +libnet_getgre_length(uint16_t fv); + +/** + * Generic Routing Encapsulation (GRE - RFC 1701) is used to encapsulate any + * protocol. Hence, the IP part of the packet is usually referred as "delivery + * header". It is then followed by the GRE header and finally the encapsulated + * packet (IP or whatever). + * As GRE is very modular, the first GRE header describes the structure of the + * header, using bits and flag to specify which fields will be present in the + * header. + * @param fv the 16 0 to 7: which fields are included in the header (checksum, + * seq. number, key, ...), bits 8 to 12: flag, bits 13 to 15: version. + * @param type which protocol is encapsulated (PPP, IP, ...) + * @param sum checksum (0 for libnet to auto-fill). + * @param offset byte offset from the start of the routing field to the first byte of the SRE + * @param key inserted by the encapsulator to authenticate the source + * @param seq sequence number used by the receiver to sort the packets + * @param len size of the GRE packet + * @param payload + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_gre(uint16_t fv, uint16_t type, uint16_t sum, +uint16_t offset, uint32_t key, uint32_t seq, uint16_t len, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Generic Routing Encapsulation (GRE - RFC 1701) is used to encapsulate any + * protocol. Hence, the IP part of the packet is usually referred as "delivery + * header". It is then followed by the GRE header and finally the encapsulated + * packet (IP or whatever). + * As GRE is very modular, the first GRE header describes the structure of the + * header, using bits and flag to specify which fields will be present in the + * header. + * @param fv the 16 0 to 7: which fields are included in the header (checksum, seq. number, key, ...), bits 8 to 12: flag, bits 13 to 15: version. + * @param type which protocol is encapsulated (PPP, IP, ...) + * @param sum checksum (0 for libnet to auto-fill). + * @param offset byte offset from the start of the routing field to the first byte of the SRE + * @param key inserted by the encapsulator to authenticate the source + * @param seq sequence number used by the receiver to sort the packets + * @param len size of the GRE packet + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_egre(uint16_t fv, uint16_t type, uint16_t sum, +uint16_t offset, uint32_t key, uint32_t seq, uint16_t len, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * @param af + * @param offset + * @param length + * @param routing + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_gre_sre(uint16_t af, uint8_t offset, uint8_t length, +uint8_t *routing, const uint8_t* payload, uint32_t payload_s, libnet_t *l, +libnet_ptag_t ptag); + +/** + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_gre_last_sre(libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an RFC 1771 Border Gateway Protocol 4 (BGP-4) header. The primary + * function of a BGP speaking system is to exchange network reachability + * information with other BGP systems. This network reachability information + * includes information on the list of Autonomous Systems (ASs) that + * reachability information traverses. This information is sufficient to + * construct a graph of AS connectivity from which routing loops may be pruned + * and some policy decisions at the AS level may be enforced. + * This function builds the base BGP header which is used as a preamble before + * any other BGP header. For example, a BGP KEEPALIVE message may be built with + * only this function, while an error notification requires a subsequent call + * to libnet_build_bgp4_notification. + * @param marker a value the receiver can predict (if the message type is not BGP OPEN, or no authentication is used, these 16 bytes are normally set as all ones) + * @param len total length of the BGP message, including the header + * @param type type code of the message (OPEN, UPDATE, NOTIFICATION or KEEPALIVE) + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_bgp4_header(uint8_t marker[LIBNET_BGP4_MARKER_SIZE], +uint16_t len, uint8_t type, const uint8_t* payload, uint32_t payload_s, +libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an RFC 1771 Border Gateway Protocol 4 (BGP-4) OPEN header. This is + * the first message sent by each side of a BGP connection. The optional + * parameters options should be constructed using the payload interface (see + * RFC 1771 for the options structures). + * @param version protocol version (should be set to 4) + * @param src_as Autonomous System of the sender + * @param hold_time used to compute the maximum allowed time between the receipt of KEEPALIVE, and/or UPDATE messages by the sender + * @param bgp_id BGP identifier of the sender + * @param opt_len total length of the optional parameters field in bytes + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_bgp4_open(uint8_t version, uint16_t src_as, uint16_t hold_time, +uint32_t bgp_id, uint8_t opt_len, const uint8_t* payload, uint32_t payload_s, +libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an RFC 1771 Border Gateway Protocol 4 (BGP-4) update header. Update + * messages are used to transfer routing information between BGP peers. + * @param unfeasible_rt_len indicates the length of the (next) "withdrawn routes" field in bytes + * @param withdrawn_rt list of IP addresses prefixes for the routes that are being withdrawn; each IP address prefix is built as a 2-tuple + * @param total_path_attr_len indicates the length of the (next) "path attributes" field in bytes + * @param path_attributes each attribute is a 3-tuple + * @param info_len indicates the length of the (next) "network layer reachability information" field in bytes (needed for internal memory size calculation) + * @param reachability_info 2-tuples . + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_bgp4_update(uint16_t unfeasible_rt_len, const uint8_t *withdrawn_rt, +uint16_t total_path_attr_len, const uint8_t *path_attributes, uint16_t info_len, +uint8_t *reachability_info, const uint8_t* payload, uint32_t payload_s, +libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds an RFC 1771 Border Gateway Protocol 4 (BGP-4) notification header. + * A NOTIFICATION message is sent when an error condition is detected. Specific + * error information may be passed through the payload interface. + * @param err_code type of notification + * @param err_subcode more specific information about the reported error. + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_bgp4_notification(uint8_t err_code, uint8_t err_subcode, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds a Sebek header. The Sebek protocol was designed by the Honeynet + * Project as a transport mechanism for post-intrusion forensic data. More + * information may be found here: http://www.honeynet.org/papers/sebek.pdf. + * @param magic identify packets that should be hidden + * @param version protocol version, currently 1 + * @param type type of record (read data is type 0, write data is type 1) + * @param counter PDU counter used to identify when packet are lost + * @param time_sec seconds since EPOCH according to the honeypot + * @param time_usec residual microseconds + * @param pid PID + * @param uid UID + * @param fd FD + * @param cmd 12 first characters of the command + * @param length length in bytes of the PDU's body + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_sebek(uint32_t magic, uint16_t version, uint16_t type, +uint32_t counter, uint32_t time_sec, uint32_t time_usec, uint32_t pid, +uint32_t uid, uint32_t fd, uint8_t cmd[SEBEK_CMD_LENGTH], uint32_t length, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds a HSRP header. HSRP is a Cisco proprietary protocol defined in + * RFC 2281 + * @param version version of the HSRP messages + * @param opcode type of message + * @param state current state of the router + * @param hello_time period in seconds between hello messages + * @param hold_time seconds that the current hello message is valid + * @param priority priority for the election process + * @param group standby group + * @param reserved reserved field + * @param authdata password + * @param virtual_ip virtual ip address + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_hsrp(uint8_t version, uint8_t opcode, uint8_t state, +uint8_t hello_time, uint8_t hold_time, uint8_t priority, uint8_t group, +uint8_t reserved, uint8_t authdata[HSRP_AUTHDATA_LENGTH], uint32_t virtual_ip, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Builds a link layer header for an initialized l. The function + * determines the proper link layer header format from how l was initialized. + * The function current supports Ethernet and Token Ring link layers. + * @param dst the destination MAC address + * @param src the source MAC address + * @param oui Organizationally Unique Identifier (unused for Ethernet) + * @param type the upper layer protocol type + * @param payload optional payload or NULL + * @param payload_s payload length or 0 + * @param l pointer to a libnet context + * @param ptag protocol tag to modify an existing header, 0 to build a new one + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_build_link(const uint8_t *dst, const uint8_t *src, const uint8_t *oui, uint16_t type, +const uint8_t* payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag); + +/** + * Automatically builds a link layer header for an initialized l. The function + * determines the proper link layer header format from how l was initialized. + * The function current supports Ethernet and Token Ring link layers. + * @param dst the destination MAC address + * @param oui Organizationally Unique Identifier (unused for Ethernet) + * @param type the upper layer protocol type + * @param l pointer to a libnet context + * @return protocol tag value on success + * @retval -1 on error + */ +LIBNET_API +libnet_ptag_t +libnet_autobuild_link(const uint8_t *dst, const uint8_t *oui, uint16_t type, +libnet_t *l); + +/** + * Writes a prebuilt packet to the network. The function assumes that l was + * previously initialized (via a call to libnet_init()) and that a + * previously constructed packet has been built inside this context (via one or + * more calls to the libnet_build* family of functions) and is ready to go. + * Depending on how libnet was initialized, the function will write the packet + * to the wire either via the raw or link layer interface. The function will + * also bump up the internal libnet stat counters which are retrievable via + * libnet_stats(). + * @param l pointer to a libnet context + * @return the number of bytes written + * @retval -1 on error + */ +LIBNET_API +int +libnet_write(libnet_t *l); + +/** + * Returns the IP address for the device libnet was initialized with. If + * libnet was initialized without a device (in raw socket mode) the function + * will attempt to find one. If the function fails and returns -1 a call to + * libnet_geterrror() will tell you why. + * @param l pointer to a libnet context + * @return a big endian IP address suitable for use in a libnet_build function + * @retval -1 + */ +LIBNET_API +uint32_t +libnet_get_ipaddr4(libnet_t *l); + +/** + * Returns the IPv6 address for the device libnet was initialized with. If + * libnet was initialized without a device (in raw socket mode) the function + * will attempt to find one. If the function fails and returns in6addr_error, a + * call to libnet_geterrror() will tell you why. + * This function is not yet implemented for Win32 platforms. + * @param l pointer to a libnet context + * @retval in6addr_error on failure + */ +LIBNET_API +struct libnet_in6_addr +libnet_get_ipaddr6(libnet_t *l); + +/** + * Returns the MAC address for the device libnet was initialized with. If + * libnet was initialized without a device the function will attempt to find + * one. If the function fails and returns NULL a call to libnet_geterror() will + * tell you why. + * @param l pointer to a libnet context + * @return a pointer to the MAC address or NULL + */ +LIBNET_API +struct libnet_ether_addr * +libnet_get_hwaddr(libnet_t *l); + +/** + * Takes a colon separated hexidecimal address (from the command line) and + * returns a bytestring suitable for use in a libnet_build function. Note this + * function performs an implicit malloc and the return value should be freed + * after its use. + * @param s the string to be parsed + * @param len the resulting size of the returned byte string + * @return a byte string or NULL on failure + */ +LIBNET_API +uint8_t * +libnet_hex_aton(const char *s, int *len); + +/** + * Returns the version of libnet. + * @return the libnet version + */ +LIBNET_API +const char * +libnet_version(void); + +/** + * [Advanced Interface] + * Yanks a prebuilt, wire-ready packet from the given libnet context. If + * libnet was configured to do so (which it is by default) the packet will have + * all checksums written in. This function is part of the advanced interface + * and is only available when libnet is initialized in advanced mode. It is + * important to note that the function performs an implicit malloc() and a + * corresponding call to libnet_adv_free_packet() should be made to free the + * memory packet occupies. If the function fails libnet_geterror() can tell you + * why. + * @param l pointer to a libnet context + * @param packet will contain the wire-ready packet + * @param packet_s will contain the packet size + * @retval 1 on success + * @retval -1 on failure + */ +LIBNET_API +int +libnet_adv_cull_packet(libnet_t *l, uint8_t **packet, uint32_t *packet_s); + +/** + * [Advanced Interface] + * Pulls the header from the specified ptag from the given libnet context. This + * function is part of the advanced interface and is only available when libnet + * is initialized in advanced mode. If the function fails libnet_geterror() can + * tell you why. + * @param l pointer to a libnet context + * @param ptag the ptag referencing the header to pull + * @param header will contain the header + * @param header_s will contain the header size + * @retval 1 on success + * @retval -1 on failure + */ +LIBNET_API +int +libnet_adv_cull_header(libnet_t *l, libnet_ptag_t ptag, uint8_t **header, +uint32_t *header_s); + +/** + * [Advanced Interface] + * Writes a packet the network at the link layer. This function is useful to + * write a packet that has been constructed by hand by the application + * programmer or, more commonly, to write a packet that has been returned by + * a call to libnet_adv_cull_packet(). This function is part of the advanced + * interface and is only available when libnet is initialized in advanced mode. + * If the function fails libnet_geterror() can tell you why. + * @param l pointer to a libnet context + * @param packet a pointer to the packet to inject + * @param packet_s the size of the packet + * @return the number of bytes written + * @retval -1 on failure + */ +LIBNET_API +int +libnet_adv_write_link(libnet_t *l, const uint8_t *packet, uint32_t packet_s); + +/** + * [Advanced Interface] + * Writes a packet the network at the raw socket layer. This function is useful + * to write a packet that has been constructed by hand by the application + * programmer or, more commonly, to write a packet that has been returned by + * a call to libnet_adv_cull_packet(). This function is part of the advanced + * interface and is only available when libnet is initialized in advanced mode. + * If the function fails libnet_geterror() can tell you why. + * @param l pointer to a libnet context + * @param packet a pointer to the packet to inject + * @param packet_s the size of the packet + * @return the number of bytes written + * @retval -1 on failure + */ +LIBNET_API +int +libnet_adv_write_raw_ipv4(libnet_t *l, const uint8_t *packet, uint32_t packet_s); + +/** + * [Advanced Interface] + * Frees the memory allocated when libnet_adv_cull_packet() is called. + * @param l pointer to a libnet context + * @param packet a pointer to the packet to free + */ +LIBNET_API +void +libnet_adv_free_packet(libnet_t *l, uint8_t *packet); + +/** + * [Context Queue] + * Adds a new context to the libnet context queue. If no queue exists, this + * function will create the queue and add the specified libnet context as the + * first entry on the list. The functions checks to ensure niether l nor label + * are NULL, and that label doesn't refer to an existing context already in the + * queue. Additionally, l should refer to a libnet context previously + * initialized with a call to libnet_init(). If the context queue in write + * locked, this function will fail. + * @param l pointer to a libnet context + * @param label a canonical name given to recognize the new context, no longer than LIBNET_LABEL_SIZE + * @retval 1 on success + * @retval -1 on failure +*/ +int +libnet_cq_add(libnet_t *l, char *label); + +/** + * [Context Queue] + * Removes a specified context from the libnet context queue by specifying the + * libnet context pointer. Note the function will remove the specified context + * from the context queue and cleanup internal memory from the queue, it is up + * to the application programmer to free the returned libnet context with a + * call to libnet_destroy(). Also, as it is not necessary to keep the libnet + * context pointer when initially adding it to the context queue, most + * application programmers will prefer to refer to entries on the context + * queue by canonical name and would use libnet_cq_remove_by_label(). If the + * context queue is write locked, this function will fail. + * @param l pointer to a libnet context + * @return the pointer to the removed libnet context + * @retval NULL on failure + */ +LIBNET_API +libnet_t * +libnet_cq_remove(libnet_t *l); + +/** + * [Context Queue] + * Removes a specified context from the libnet context queue by specifying the + * canonical name. Note the function will remove the specified context from + * the context queue and cleanup internal memory from the queue, it is up to + * the application programmer to free the returned libnet context with a call + * to libnet_destroy(). If the context queue is write locked, this function + * will fail. + * @param label canonical name of the context to remove + * @return the pointer to the removed libnet context + * @retval NULL on failure + */ +LIBNET_API +libnet_t * +libnet_cq_remove_by_label(char *label); + +/** + * [Context Queue] + * Returns the canonical label associated with the context. + * @param l pointer to a libnet context + * @return pointer to the libnet context's label + */ +LIBNET_API +const char * +libnet_cq_getlabel(libnet_t *l); + +/** + * [Context Queue] + * Locates a libnet context from the queue, indexed by a canonical label. + * @param label canonical label of the libnet context to retrieve + * @return the expected libnet context + * @retval NULL on failure + */ +LIBNET_API +libnet_t * +libnet_cq_find_by_label(char *label); + +/** + * [Context Queue] + * Destroys the entire context queue, calling libnet_destroy() on each + * member context. + */ +LIBNET_API +void +libnet_cq_destroy(void); + +/** + * [Context Queue] + * Intiailizes the interator interface and set a write lock on the entire + * queue. This function is intended to be called just prior to interating + * through the entire list of contexts (with the probable intent of inject a + * series of packets in rapid succession). This function is often used as + * per the following: + * + * for (l = libnet_cq_head(); libnet_cq_last(); l = libnet_cq_next()) + * { + * ... + * } + * + * Much of the time, the application programmer will use the iterator as it is + * written above; as such, libnet provides a macro to do exactly that, + * for_each_context_in_cq(l). Warning: do not call the iterator more than once + * in a single loop. + * @return the head of the context queue + */ +LIBNET_API +libnet_t * +libnet_cq_head(void); + +/** + * [Context Queue] + * Check whether the iterator is at the last context in the queue. + * @retval 1 if at the end of the context queue + * @retval 0 otherwise + */ +LIBNET_API +int +libnet_cq_last(void); + +/** + * [Context Queue] + * Get next context from the context queue. + * @return the next context from the context queue + */ +LIBNET_API +libnet_t * +libnet_cq_next(void); + +/** + * [Context Queue] + * Function returns the number of libnet contexts that are in the queue. + * @return the number of libnet contexts currently in the queue + */ +LIBNET_API +uint32_t +libnet_cq_size(void); + +/** + * [Context Queue] + */ +LIBNET_API +uint32_t +libnet_cq_end_loop(void); + +/** + * [Diagnostic] + * Prints the contents of the given context. + * @param l pointer to a libnet context + */ +LIBNET_API +void +libnet_diag_dump_context(libnet_t *l); + +/** + * [Diagnostic] + * Prints the contents of every pblock. + * @param l pointer to a libnet context + */ +LIBNET_API +void +libnet_diag_dump_pblock(libnet_t *l); + +/** + * [Diagnostic] + * Returns the canonical name of the pblock type. + * @param type pblock type + * @return a string representing the pblock type type + * @retval "unknown" for an unknown value + */ +LIBNET_API +char * +libnet_diag_dump_pblock_type(uint8_t type); + +/** + * [Diagnostic] + * Function prints the contents of the supplied buffer to the supplied + * stream pointer. Will swap endianness based disposition of mode variable. + * Useful to be used in conjunction with the advanced interface and a culled + * packet. + * @param packet the packet to print + * @param len length of the packet in bytes + * @param swap 1 to swap byte order, 0 to not. + * Counter-intuitively, it is necessary to swap in order to see the byte + * order as it is on the wire (this may be a bug). + * @param stream a stream pointer to print to + */ +void +libnet_diag_dump_hex(const uint8_t *packet, uint32_t len, int swap, FILE *stream); + +/* + * [Internal] + */ +LIBNET_API +int +libnet_write_raw_ipv4(libnet_t *l, const uint8_t *packet, uint32_t size); + +/* + * [Internal] + */ +LIBNET_API +int +libnet_write_raw_ipv6(libnet_t *l, const uint8_t *packet, uint32_t size); + +/* + * [Internal] + */ +LIBNET_API +int +libnet_write_link(libnet_t *l, const uint8_t *packet, uint32_t size); + +/* + * [Internal] + */ +int +libnet_open_raw4(libnet_t *l); + +/* + * [Internal] + */ +LIBNET_API +int +libnet_close_raw4(libnet_t *l); + +/* + * [Internal] + */ +int +libnet_open_raw6(libnet_t *l); + +/* + * [Internal] + */ +int +libnet_close_raw6(libnet_t *l); + +/* + * [Internal] + */ +int +libnet_select_device(libnet_t *l); + +/* + * [Internal] + */ +int +libnet_open_link(libnet_t *l); + +/* + * [Internal] + */ +int +libnet_close_link(libnet_t *l); + +/* + * [Internal] + * THIS FUNCTION IS BROKEN. IT WILL SEGFAULT OR CORRUPT MEMORY, OR JUST SILENTLY DO THE + * WRONG THING IF NOT CALLED CORRECTLY, AND CALLING IT CORRECTLY IS UNDOCUMENTED, AND + * ALMOST IMPOSSIBLE. YOU HAVE BEEN WARNED. + */ +int +libnet_do_checksum(libnet_t *l, uint8_t *iphdr, int protocol, int h_len); + +/* Calculate internet checksums. + * + * IP (TCP, UDP, IGMP, ICMP, etc...) checksums usually need information from + * the IP header to construct the "pseudo header", this function takes a + * pointer to that header, the buffer boundaries, the "h_len" (see pblock_t for + * a description, it is increasingly unused, though, and I'm trying to remove it + * altogether), and the protocol number for the protocol that is to be + * checksummed. + * + * Finding that protocol requires that the IP header be well-formed... so this + * won't work well for invalid packets. But then, what is the valid checksum + * for a invalid packet, anyhow? + * + * This doesn't work well for non-inet checksums, sorry, that's an original design + * flaw. pblock_t needs a pointer in it, to a packet assembly function that can be + * called at runtime to do assembly and checksumming. + */ +LIBNET_API +int +libnet_inet_checksum(libnet_t *l, uint8_t *iphdr, int protocol, int h_len, const uint8_t *beg, const uint8_t * end); + +/* + * [Internal] + */ +LIBNET_API +uint32_t +libnet_compute_crc(uint8_t *buf, uint32_t len); + +/* + * [Internal] + */ +LIBNET_API +uint16_t +libnet_ip_check(uint16_t *addr, int len); + +/* + * [Internal] + */ +LIBNET_API +int +libnet_in_cksum(uint16_t *addr, int len); + +/* + * [Internal] + * If ptag is 0, function will create a pblock for the protocol unit type, + * append it to the list and return a pointer to it. If ptag is not 0, + * function will search the pblock list for the specified protocol block + * and return a pointer to it. + */ +LIBNET_API +libnet_pblock_t * +libnet_pblock_probe(libnet_t *l, libnet_ptag_t ptag, uint32_t b_len, +uint8_t type); + +/* + * [Internal] + * Function creates the pblock list if l->protocol_blocks == NULL or appends + * an entry to the doubly linked list. + */ +LIBNET_API +libnet_pblock_t * +libnet_pblock_new(libnet_t *l, uint32_t b_len); + +/* + * [Internal] + * Function swaps two pblocks in memory. + */ +LIBNET_API +int +libnet_pblock_swap(libnet_t *l, libnet_ptag_t ptag1, libnet_ptag_t ptag2); + +/* + * [Internal] + * Function inserts ptag2 before ptag1 in the doubly linked list. + */ +LIBNET_API +int +libnet_pblock_insert_before(libnet_t *l, libnet_ptag_t ptag1, +libnet_ptag_t ptag2); + +/* + * [Internal] + * Function removes a pblock from context + */ +LIBNET_API +void +libnet_pblock_delete(libnet_t *l, libnet_pblock_t *p); + +/* + * [Internal] + * Function updates the pblock meta-information. Internally it updates the + * ptag with a monotonically increasing variable kept in l. This way each + * pblock has a successively increasing ptag identifier. + */ +LIBNET_API +libnet_ptag_t +libnet_pblock_update(libnet_t *l, libnet_pblock_t *p, uint32_t h, uint8_t type); + + +/* + * [Internal] + * Function locates a given block by it's ptag. + */ +LIBNET_API +libnet_pblock_t * +libnet_pblock_find(libnet_t *l, libnet_ptag_t ptag); + +/* + * [Internal] + * Function copies protocol block data over. + */ +LIBNET_API +int +libnet_pblock_append(libnet_t *l, libnet_pblock_t *p, const void *buf, uint32_t len); + +/* + * [Internal] + * Function sets pblock flags. + */ +LIBNET_API +void +libnet_pblock_setflags(libnet_pblock_t *p, uint8_t flags); + +/* + * [Internal] + * Function returns the protocol number for the protocol block type. If + * the type is unknown, the function defaults to returning IPPROTO_IP. + */ +LIBNET_API +int +libnet_pblock_p2p(uint8_t type); + +/* + * [Internal] + * Function assembles the protocol blocks into a packet, checksums are + * calculated if that was requested. + */ +LIBNET_API +int +libnet_pblock_coalesce(libnet_t *l, uint8_t **packet, uint32_t *size); + +#if !(__WIN32__) +/* + * [Internal] + * By testing if we can retrieve the FLAGS of an interface + * we can know if it exists or not and if it is up. + */ +int +libnet_check_iface(libnet_t *l); +#endif + +#if defined(__WIN32__) +/* + * [Internal] + */ +BYTE * +libnet_win32_get_remote_mac(libnet_t *l, DWORD IP); + +/* + * [Internal] + */ +int +libnet_close_link_interface(libnet_t *l); + +/* + * [Internal] + */ +BYTE * +libnet_win32_read_arp_table(DWORD IP); +#endif +#endif /* __LIBNET_FUNCTIONS_H */ + +/** + * Local Variables: + * indent-tabs-mode: nil + * c-file-style: "stroustrup" + * End: + */ diff --git a/source/tools/detect/net_diag/tcpping/include/libnet/libnet-headers.h b/source/tools/detect/net_diag/tcpping/include/libnet/libnet-headers.h new file mode 100644 index 0000000000000000000000000000000000000000..afbb5c39105993f5646ac8b1864e5ae86bcab955 --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/include/libnet/libnet-headers.h @@ -0,0 +1,1921 @@ +/* + * + * libnet-headers.h - Network routine library headers header file + * + * Copyright (c) 1998 - 2004 Mike D. Schiffman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef __LIBNET_HEADERS_H +#define __LIBNET_HEADERS_H +/* + * @file libnet-headers.h + * @brief libnet header information + */ + +/* + * Libnet defines header sizes for every builder function exported. + */ +#define LIBNET_802_1Q_H 0x12 /**< 802.1Q header: 18 bytes */ +#define LIBNET_802_1X_H 0x04 /**< 802.1X header: 4 bytes */ +#define LIBNET_802_2_H 0x03 /**< 802.2 LLC header: 3 bytes */ +#define LIBNET_802_2SNAP_H 0x08 /**< 802.2 LLC/SNAP header:8 bytes */ +#define LIBNET_802_3_H 0x0e /**< 802.3 header: 14 bytes */ +#define LIBNET_ARP_H 0x08 /**< ARP header w/o addrs: 8 bytes */ +#define LIBNET_ARP_ETH_IP_H 0x1c /**< ARP w/ ETH and IP: 28 bytes */ +#define LIBNET_BGP4_HEADER_H 0x13 /**< BGP header: 19 bytes */ +#define LIBNET_BGP4_OPEN_H 0x0a /**< BGP open header: 10 bytes */ +#define LIBNET_BGP4_UPDATE_H 0x04 /**< BGP open header: 4 bytes */ +#define LIBNET_BGP4_NOTIFICATION_H 0x02 /**< BGP notif. header: 2 bytes */ +#define LIBNET_CDP_H 0x08 /**< CDP header base: 8 bytes */ +#define LIBNET_LLDP_H 0x02 /**< LLDP header base: 2 bytes */ +#define LIBNET_DHCPV4_H 0xf0 /**< DHCP v4 header: 240 bytes */ +#define LIBNET_UDP_DNSV4_H 0x0c /**< UDP DNS v4 header: 12 bytes */ +#define LIBNET_TCP_DNSV4_H 0x0e /**< TCP DNS v4 header: 14 bytes */ +#define LIBNET_ETH_H 0x0e /**< Ethernet header: 14 bytes */ +#define LIBNET_FDDI_H 0x15 /**< FDDI header: 21 bytes */ +#define LIBNET_ICMPV4_H 0x04 /**< ICMP header base: 4 bytes */ +#define LIBNET_ICMPV4_ECHO_H 0x08 /**< ICMP_ECHO header: 8 bytes */ +#define LIBNET_ICMPV4_MASK_H 0x0c /**< ICMP_MASK header: 12 bytes */ +#define LIBNET_ICMPV4_UNREACH_H 0x08 /**< ICMP_UNREACH header: 8 bytes */ +#define LIBNET_ICMPV4_TIMXCEED_H 0x08 /**< ICMP_TIMXCEED header: 8 bytes */ +#define LIBNET_ICMPV4_REDIRECT_H 0x08 /**< ICMP_REDIRECT header: 8 bytes */ +#define LIBNET_ICMPV4_TS_H 0x14 /**< ICMP_TIMESTAMP headr:20 bytes */ +#define LIBNET_ICMPV6_COMMON_H 0x04 /**< ICMP6 header base: 4 bytes */ +#define LIBNET_ICMPV6_H 0x08 /**< ICMP6 header base: 8 bytes (unused, for backwards compatibility) */ +#define LIBNET_ICMPV6_UNREACH_H 0x08 /**< ICMP6 unreach base: 8 bytes */ +#define LIBNET_ICMPV6_ECHO_H 0x08 /**< ICMP6 echo: 8 bytes */ +#define LIBNET_ICMPV6_NDP_NSOL_H 24 /**< ICMP6 NDP NSOL: 24 bytes */ +#define LIBNET_ICMPV6_NDP_NADV_H 24 /**< ICMP6 NDP NADV: 24 bytes */ +#define LIBNET_ICMPV6_NDP_OPT_H 0x02 /**< ICMP6 NDP OPT base: 2 bytes */ +#define LIBNET_IGMP_H 0x08 /**< IGMP header: 8 bytes */ +#define LIBNET_IPV4_H 0x14 /**< IPv4 header: 20 bytes */ +#define LIBNET_IPV6_H 0x28 /**< IPv6 header: 40 bytes */ +#define LIBNET_IPV6_FRAG_H 0x08 /**< IPv6 frag header: 8 bytes */ +#define LIBNET_IPV6_ROUTING_H 0x04 /**< IPv6 frag header base:4 bytes */ +#define LIBNET_IPV6_DESTOPTS_H 0x02 /**< IPv6 dest opts base: 2 bytes */ +#define LIBNET_IPV6_HBHOPTS_H 0x02 /**< IPv6 hop/hop opt base:2 bytes */ +#define LIBNET_IPSEC_ESP_HDR_H 0x0c /**< IPSEC ESP header: 12 bytes */ +#define LIBNET_IPSEC_ESP_FTR_H 0x02 /**< IPSEC ESP footer: 2 bytes */ +#define LIBNET_IPSEC_AH_H 0x10 /**< IPSEC AH header: 16 bytes */ +#define LIBNET_ISL_H 0x1a /**< ISL header: 26 bytes */ +#define LIBNET_GRE_H 0x04 /**< GRE header: 4 bytes */ +#define LIBNET_GRE_SRE_H 0x04 /**< GRE SRE header: 4 bytes */ +#define LIBNET_MPLS_H 0x04 /**< MPLS header: 4 bytes */ +#define LIBNET_OSPF_H 0x10 /**< OSPF header: 16 bytes */ +#define LIBNET_OSPF_HELLO_H 0x18 /**< OSPF hello header: 24 bytes */ +#define LIBNET_OSPF_DBD_H 0x08 /**< OSPF DBD header: 8 bytes */ +#define LIBNET_OSPF_LSR_H 0x0c /**< OSPF LSR header: 12 bytes */ +#define LIBNET_OSPF_LSU_H 0x04 /**< OSPF LSU header: 4 bytes */ +#define LIBNET_OSPF_LSA_H 0x14 /**< OSPF LSA header: 20 bytes */ +#define LIBNET_OSPF_AUTH_H 0x08 /**< OSPF AUTH header: 8 bytes */ +#define LIBNET_OSPF_CKSUM 0x10 /**< OSPF CKSUM header: 16 bytes */ +#define LIBNET_OSPF_LS_RTR_H 0x10 /**< OSPF LS RTR header: 16 bytes */ +#define LIBNET_OSPF_LS_NET_H 0x08 /**< OSPF LS NET header: 8 bytes */ +#define LIBNET_OSPF_LS_SUM_H 0x0c /**< OSPF LS SUM header: 12 bytes */ +#define LIBNET_OSPF_LS_AS_EXT_H 0x10 /**< OSPF LS AS header: 16 bytes */ +#define LIBNET_NTP_H 0x30 /**< NTP header: 48 bytes */ +#define LIBNET_RIP_H 0x18 /**< RIP header base: 24 bytes */ +#define LIBNET_RPC_CALL_H 0x28 /**< RPC header: 40 bytes + * (assuming 8 byte auth header) + */ +#define LIBNET_RPC_CALL_TCP_H 0x2c /**< RPC header: 44 bytes + * (with record marking) + */ +#define LIBNET_SEBEK_H 0x30 /* sebek header: 48 bytes */ +#define LIBNET_STP_CONF_H 0x23 /**< STP conf header: 35 bytes */ +#define LIBNET_STP_TCN_H 0x04 /**< STP tcn header: 4 bytes */ +#define LIBNET_TOKEN_RING_H 0x16 /**< Token Ring header: 22 bytes */ +#define LIBNET_TCP_H 0x14 /**< TCP header: 20 bytes */ +#define LIBNET_UDP_H 0x08 /**< UDP header: 8 bytes */ +#define LIBNET_VRRP_H 0x08 /**< VRRP header: 8 bytes */ +#define LIBNET_HSRP_H 0x14 /**< HSRP header: 8 bytes */ + +/* + * IEEE 802.1Q (Virtual Local Area Network) VLAN header, static header + * size: 18 bytes + */ +struct libnet_802_1q_hdr +{ + uint8_t vlan_dhost[ETHER_ADDR_LEN]; /**< destination ethernet address */ + uint8_t vlan_shost[ETHER_ADDR_LEN]; /**< source ethernet address */ + uint16_t vlan_tpi; /**< tag protocol ID */ + uint16_t vlan_priority_c_vid; /**< priority | VLAN ID */ +#define LIBNET_802_1Q_PRIMASK 0x0007 /**< priority mask */ +#define LIBNET_802_1Q_CFIMASK 0x0001 /**< CFI mask */ +#define LIBNET_802_1Q_VIDMASK 0x0fff /**< vid mask */ + uint16_t vlan_len; /**< length or type (802.3 / Eth 2) */ +}; + +/* + * IEEE 802.1X EAP (Extensible Authentication Protocol) header, static header + * size: 4 bytes + */ +struct libnet_802_1x_hdr +{ + uint8_t dot1x_version; /**< protocol version */ + uint8_t dot1x_type; /**< frame type */ +#define LIBNET_802_1X_PACKET 0x00 /**< 802.1x packet */ +#define LIBNET_802_1X_START 0x01 /**< 802.1x start */ +#define LIBNET_802_1X_LOGOFF 0x02 /**< 802.1x logoff */ +#define LIBNET_802_1X_KEY 0x03 /**< 802.1x key */ +#define LIBNET_802_1X_ENCASFAL 0x04 /**< 802.1x encasfal */ + uint16_t dot1x_length; /**< total frame length */ +}; + +/* + * IEEE 802.2 LLC header + * Link Layer Control + * static header size: 3 bytes + */ +struct libnet_802_2_hdr +{ + uint8_t llc_dsap; /* destination service access point */ + uint8_t llc_ssap; /* source service access point */ +#define LIBNET_SAP_STP 0x42 +#define LIBNET_SAP_SNAP 0xaa + uint8_t llc_control; /* control field */ +}; + + +/* + * IEEE 802.2 LLC/SNAP header + * SubNetwork Attachment Point + * static header size: 8 bytes + */ +struct libnet_802_2snap_hdr +{ + uint8_t snap_dsap; /* destination service access point */ + uint8_t snap_ssap; /* destination service access point */ + uint8_t snap_control; /* control field */ + uint8_t snap_oui[3]; /* OUI */ + uint16_t snap_type; /* type */ +}; + + +/* + * 802.3 header + * IEEE Ethernet + * Static header size: 14 bytes + */ +struct libnet_802_3_hdr +{ + uint8_t _802_3_dhost[ETHER_ADDR_LEN];/* destination ethernet address */ + uint8_t _802_3_shost[ETHER_ADDR_LEN];/* source ethernet address */ + uint16_t _802_3_len; /* packet type ID */ +}; + + +/* + * ARP header + * Address Resolution Protocol + * Base header size: 8 bytes + */ +struct libnet_arp_hdr +{ + uint16_t ar_hrd; /* format of hardware address */ +#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */ +#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */ +#define ARPHRD_EETHER 2 /* Experimental Ethernet */ +#define ARPHRD_AX25 3 /* AX.25 Level 2 */ +#define ARPHRD_PRONET 4 /* PROnet token ring */ +#define ARPHRD_CHAOS 5 /* Chaosnet */ +#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */ +#define ARPHRD_ARCNET 7 /* ARCnet */ +#define ARPHRD_APPLETLK 8 /* APPLEtalk */ +#define ARPHRD_LANSTAR 9 /* Lanstar */ +#define ARPHRD_DLCI 15 /* Frame Relay DLCI */ +#define ARPHRD_ATM 19 /* ATM */ +#define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */ +#define ARPHRD_IPSEC 31 /* IPsec tunnel */ + uint16_t ar_pro; /* format of protocol address */ + uint8_t ar_hln; /* length of hardware address */ + uint8_t ar_pln; /* length of protocol address */ + uint16_t ar_op; /* operation type */ +#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 */ + /* address information allocated dynamically */ +}; + +/* + * BGP4 header + * Border Gateway Protocol 4 + * Base header size : 19 bytes + */ +struct libnet_bgp4_header_hdr +{ +#define LIBNET_BGP4_MARKER_SIZE 16 + uint8_t marker[LIBNET_BGP4_MARKER_SIZE]; + uint16_t len; + uint8_t type; +#define LIBNET_BGP4_OPEN 1 +#define LIBNET_BGP4_UPDATE 2 +#define LIBNET_BGP4_NOTIFICATION 3 +#define LIBNET_BGP4_KEEPALIVE 4 +}; + +/* + * BGP4 open header + * Border Gateway Protocol 4 + * Base header size : 10 bytes + */ +struct libnet_bgp4_open_hdr +{ + uint8_t version; + uint16_t src_as; + uint16_t hold_time; + uint32_t bgp_id; + uint8_t opt_len; +}; + +/* + * BGP4 notification message + * + * Border Gateway Protocol 4 + * Base header size : 2 bytes + * + * Use payload if you need data + */ +struct libnet_bgp4_notification_hdr +{ +#define LIBNET_BGP4_MESSAGE_HEADER_ERROR 1 +#define LIBNET_BGP4_OPEN_MESSAGE_ERROR 2 +#define LIBNET_BGP4_UPDATE_MESSAGE_ERROR 3 +#define LIBNET_BGP4_HOLD_TIMER_EXPIRED 4 +#define LIBNET_BGP4_FINITE_STATE__ERROR 5 +#define LIBNET_BGP4_CEASE 6 + uint8_t err_code; + +/* Message Header Error subcodes */ +#define LIBNET_BGP4_CONNECTION_NOT_SYNCHRONIZED 1 +#define LIBNET_BGP4_BAD_MESSAGE_LENGTH 2 +#define LIBNET_BGP4_BAD_MESSAGE_TYPE 3 +/* OPEN Message Error subcodes */ +#define LIBNET_BGP4_UNSUPPORTED_VERSION_NUMBER 1 +#define LIBNET_BGP4_BAD_PEER_AS 2 +#define LIBNET_BGP4_BAD_BGP_IDENTIFIER 3 +#define LIBNET_BGP4_UNSUPPORTED_OPTIONAL_PARAMETER 4 +#define LIBNET_BGP4_AUTHENTICATION_FAILURE 5 +#define LIBNET_BGP4_UNACCEPTABLE_HOLD_TIME 6 +/* UPDATE Message Error subcodes */ +#define LIBNET_BGP4_MALFORMED_ATTRIBUTE_LIST +#define LIBNET_BGP4_UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE +#define LIBNET_BGP4_MISSING_WELL_KNOWN_ATTRIBUTE +#define LIBNET_BGP4_ATTRIBUTE_FLAGS_ERROR +#define LIBNET_BGP4_ATTRIBUTE_LENGTH_ERROR +#define LIBNET_BGP4_INVALID_ORIGIN_ATTRIBUTE +#define LIBNET_BGP4_AS_ROUTING_LOOP +#define LIBNET_BGP4_INVALID_NEXT_HOP_ATTRIBUTE +#define LIBNET_BGP4_OPTIONAL_ATTRIBUTE_ERROR +#define LIBNET_BGP4_INVALID_NETWORK_FIELD +#define LIBNET_BGP4_MALFORMED_AS_PATH + uint8_t err_subcode; +}; + +/* + * LLDP header + * Link Layer Discovery Protocol + * Base header size : 2 bytes + */ +struct libnet_lldp_hdr +{ +#define LIBNET_LLDP_ETH_TYPE (0x88cc) /* LLDP Ethernet type */ + +#define LIBNET_LLDP_TLV_HDR_SIZE 0x02 /* LLDP TLV's header size 2 bytes */ +#define LIBNET_LLDP_SUBTYPE_SIZE 0x01 /* LLDP Subtype field size 2 bytes */ + uint16_t tlv_info; /* Type = 7 bits, Length = 9 bits */ + +/* Mandatory TLVs Types */ +#define LIBNET_LLDP_END_LLDPDU 0x00 /* End of LLDPDU (Mandatory) */ + +#define LIBNET_LLDP_CHASSIS_ID 0x01 /* Chassis ID (Mandatory) */ + #define LIBNET_LLDP_CHASSIS_ID_SUBTYPE_RESERVED 0x00 + #define LIBNET_LLDP_CHASSIS_ID_SUBTYPE_COMPONENT 0x01 /* Chassis Component */ + #define LIBNET_LLDP_CHASSIS_ID_SUBTYPE_IF_ALIAS 0x02 /* Interface Alias */ + #define LIBNET_LLDP_CHASSIS_ID_SUBTYPE_PORT 0x03 /* Port Component */ + #define LIBNET_LLDP_CHASSIS_ID_SUBTYPE_MAC 0x04 /* MAC Address */ + #define LIBNET_LLDP_CHASSIS_ID_SUBTYPE_NETWORK 0x05 /* Network Address */ + #define LIBNET_LLDP_CHASSIS_ID_SUBTYPE_IF_NAME 0x06 /* Interface Name */ + #define LIBNET_LLDP_CHASSIS_ID_SUBTYPE_LOCALLY 0x07 /* Locally Assigned */ + +#define LIBNET_LLDP_PORT_ID 0x02 /* Port ID (Mandatory) */ + #define LIBNET_LLDP_PORT_ID_SUBTYPE_RESERVED 0x00 + #define LIBNET_LLDP_PORT_ID_SUBTYPE_IF_ALIAS 0x01 /* Interface Alias */ + #define LIBNET_LLDP_PORT_ID_SUBTYPE_MAC 0x03 /* MAC Address */ + #define LIBNET_LLDP_PORT_ID_SUBTYPE_NETWORK 0x04 /* Network Address */ + #define LIBNET_LLDP_PORT_ID_SUBTYPE_IF_NAME 0x05 /* Interface Name */ + #define LIBNET_LLDP_PORT_ID_SUBTYPE_AGENT_ID 0x06 /* Agent circuit ID */ + #define LIBNET_LLDP_PORT_ID_SUBTYPE_LOCALLY 0x07 /* Locally Assigned */ + /* 8 - 255 Reserved */ + +#define LIBNET_LLDP_TTL 0x03 /* Time To Live (Mandatory) */ + +/* Optional TLVs Types */ +/* Organization Specific TLV */ +#define LIBNET_LLDP_ORG_SPEC 0x7f /* Organizationally Specific TLV type = 127 */ + +#define LIBNET_LLDP_IEEE802_1 0x0080c2 /* IEEE 802.1 */ + #define LIBNET_LLDP_IEEE802_1_SUB_PORT_VLAN_ID 0x01 /* IEEE 802.1 Port VLAN ID TLV Subtype */ + #define LIBNET_LLDP_IEEE802_1_SUB_PORT_PROTO 0x02 /* IEEE 802.1 Port and Protocol VLAN ID TLV Subtype */ + #define LIBNET_LLDP_IEEE802_1_SUB_VLAN_NAME 0x03 /* IEEE 802.1 VLAN Name TLV Subtype */ + #define LIBNET_LLDP_IEEE802_1_SUB_PROTO_ID 0x04 /* IEEE 802.1 Protocol Identity TLV Subtype */ + #define LIBNET_LLDP_IEEE802_1_SUB_VID_USAGE 0x05 /* IEEE 802.1 VID Usage Digest TLV Subtype */ + #define LIBNET_LLDP_IEEE802_1_SUB_MNGMNT_VID 0x06 /* IEEE 802.1 Management VID TLV Subtype */ + #define LIBNET_LLDP_IEEE802_1_SUB_LINK_AGGR 0x07 /* IEEE 802.1 Link Aggregation TLV Subtype */ + #define LIBNET_LLDP_IEEE802_1_SUB_CONG_NOTIF 0x08 /* IEEE 802.1 Congestion Notification TLV Subtype */ + #define LIBNET_LLDP_IEEE802_1_SUB_ETS_CONFIG 0x09 /* IEEE 802.1 ETS Configuration TLV Subtype */ + #define LIBNET_LLDP_IEEE802_1_SUB_ETS_RECOM 0x0a /* IEEE 802.1 ETC Recommendation TLV Subtype */ + #define LIBNET_LLDP_IEEE802_1_SUB_PRIORITY 0x0b /* IEEE 802.1 Priority-based Flow Control Configuration TLV Subtype */ + #define LIBNET_LLDP_IEEE802_1_SUB_APP_PRIORITY 0x0c /* IEEE 802.1 Application Pririty TLV Subtype */ + #define LIBNET_LLDP_IEEE802_1_SUB_EVB 0x0d /* IEEE 802.1 EVB TLV Subtype */ + #define LIBNET_LLDP_IEEE802_1_SUB_CDCP 0x0e /* IEEE 802.1 CDCP TLV Subtype */ + #define LIBNET_LLDP_IEEE802_1_SUB_PORT_EXTNSN 0x0f /* IEEE 802.1 Port Extension TLV Subtype */ + +#define LIBNET_LLDP_IEEE802_3 0x00120f /* IEEE 802.3 */ + #define LIBNET_LLDP_IEEE802_3_SUB_MAC_PHY 0x01 /* IEEE802.3 MAC/PHY Configuration/Status TLV Subtype */ + #define LIBNET_LLDP_IEEE802_3_SUB_POWER 0x02 /* IEEE802.3 Power Via MDI TLV Subtype */ + #define LIBNET_LLDP_IEEE802_3_SUB_LINK_AGGR 0x03 /* IEEE802.3 Link Aggregation TLV Subtype */ + #define LIBNET_LLDP_IEEE802_3_SUB_MAX_FRAME_SIZE 0x04 /* IEEE802.3 Maximum Frame Size TLV Subtype */ + +#define LIBNET_LLDP_TIA_TR_41 0x0012bb /* TIA TR-41 Committee - Media Endpoint Discovery (LLDP-MED, ANSI/TIA-1057) */ + #define LIBNET_LLDP_TIA_TR_41_SUB_CAPAB 0x01 /* TIA TR-41 Committee LLDP-MED Capabilities TLV Subtype */ + #define LIBNET_LLDP_TIA_TR_41_SUB_NET_POLIC 0x02 /* TIA TR-41 Committee Network Policy TLV Subtype */ + #define LIBNET_LLDP_TIA_TR_41_SUB_LOCAL_ID 0x03 /* TIA TR-41 Committee Local Identification TLV Subtype */ + #define LIBNET_LLDP_TIA_TR_41_SUB_EXT_POWER 0x04 /* TIA TR-41 Committee Extended Power-via-MDI TLV Subtype */ + #define LIBNET_LLDP_TIA_TR_41_SUB_INV_HRDWR_REV 0x05 /* TIA TR-41 Committee Inventory - Hardware Revision TLV Subtype */ + #define LIBNET_LLDP_TIA_TR_41_SUB_INV_FRMWR_REV 0x06 /* TIA TR-41 Committee Inventory - Firmware Revision TLV Subtype */ + #define LIBNET_LLDP_TIA_TR_41_SUB_INV_SFTWR_REV 0x07 /* TIA TR-41 Committee Inventory - Inventory - Software Revision TLV Subtype */ + #define LIBNET_LLDP_TIA_TR_41_SUB_INV_SERIAL_NUM 0x08 /* TIA TR-41 Committee Inventory - Serial Number TLV Subtype */ + #define LIBNET_LLDP_TIA_TR_41_SUB_INV_MAN_NAME 0x09 /* TIA TR-41 Committee Inventory - Manufacturer Name TLV Subtype */ + #define LIBNET_LLDP_TIA_TR_41_SUB_INV_MOD_NAME 0x0a /* TIA TR-41 Committee Inventory - Model Name TLV Subtype */ + #define LIBNET_LLDP_TIA_TR_41_SUB_INV_ASSET_ID 0x0b /* TIA TR-41 Committee Inventory - Asset ID TLV Subtype */ + +#define LIBNET_LLDP_PROFIBUS 0x000ecf /* PROFIBUS International (PNO) Extension for PROFINET discovery information */ + #define LIBNET_LLDP_PROFIBUS_DELAY_VALS 0x01 /* PROFINET Measured Delay Values TLV Subtype */ + #define LIBNET_LLDP_PROFIBUS_PORT_STATUS 0x02 /* PROFINET Measured Port Status TLV Subtype */ + #define LIBNET_LLDP_PROFIBUS_ALIAS 0x03 /* PROFINET Alias TLV Subtype */ + #define LIBNET_LLDP_PROFIBUS_MRP_PORT_STAT 0x04 /* PROFINET MRP Port Status TLV Subtype */ + #define LIBNET_LLDP_PROFIBUS_CHASSIS_MAC 0x05 /* PROFINET Chassis MAC TLV Subtype */ + #define LIBNET_LLDP_PROFIBUS_PTC_STATUS 0x06 /* PROFINET PTC Status TLV Subtype */ + +#define LIBNET_LLDP_HYTEC 0x30b216 /* Hytec Geraetebau GmbH Extensions */ + #define LIBNET_LLDP_HYTEC_TRANS 0x01 /* Hytec Transceiver TLV Subtype */ + #define LIBNET_LLDP_HYTEC_TRACE 0x02 /* Hytec Trace TLV Subtype */ +}; + +/* + * For checksum stuff -- IANA says 135-254 is "unassigned" as of 12.2001. + * Let's hope this one stays that way for a while! + */ +#define LIBNET_PROTO_CDP 200 + +/* + * CDP header + * Cisco Discovery Protocol + * Base header size: 8 bytes + */ +struct libnet_cdp_hdr +{ + uint8_t cdp_version; /* version (should always be 0x01) */ + uint8_t cdp_ttl; /* time receiver should hold info in this packet */ + uint16_t cdp_sum; /* checksum */ + uint16_t cdp_type; /* type */ +#define LIBNET_CDP_DEVID 0x1 /* device id */ +#define LIBNET_CDP_ADDRESS 0x2 /* address */ +#define LIBNET_CDP_PORTID 0x3 /* port id */ +#define LIBNET_CDP_CAPABIL 0x4 /* capabilities */ +#define LIBNET_CDP_VERSION 0x5 /* version */ +#define LIBNET_CDP_PLATFORM 0x6 /* platform */ +#define LIBNET_CDP_IPPREFIX 0x7 /* ip prefix */ + uint16_t cdp_len; /* type + length + value */ + /* value information done dynamically */ + +/* CDP capabilities */ +#define LIBNET_CDP_CAP_L3R 0x01/* performs level 3 routing */ +#define LIBNET_CDP_CAP_L2B 0x02/* performs level 2 transparent bridging */ +#define LIBNET_CDP_CAP_L2SRB 0x04/* performs level 2 sourceroute bridging */ +#define LIBNET_CDP_CAP_L2S 0x08/* performs level 2 switching */ +#define LIBNET_CDP_CAP_SR 0x10/* sends and recieves packets on a network */ +#define LIBNET_CDP_CAP_NOI 0x20/* does not forward IGMP on non-router ports */ +#define LIBNET_CDP_CAP_L1F 0x40/* provides level 1 functionality */ +}; + + +/* + * Used as an overlay for type/len/values + */ +#define LIBNET_CDP_VALUE_H 0x04 /*< CDP value header base: 4 bytes */ +struct libnet_cdp_value_hdr +{ + uint16_t cdp_type; + uint16_t cdp_len; +}; + + +/* + * DHCP header + * Dynamic Host Configuration Protocol + * Static header size: f0 bytes + */ +struct libnet_dhcpv4_hdr +{ + uint8_t dhcp_opcode; /* opcode */ +#define LIBNET_DHCP_REQUEST 0x1 +#define LIBNET_DHCP_REPLY 0x2 + uint8_t dhcp_htype; /* hardware address type */ + uint8_t dhcp_hlen; /* hardware address length */ + uint8_t dhcp_hopcount; /* used by proxy servers */ + uint32_t dhcp_xid; /* transaction ID */ + uint16_t dhcp_secs; /* number of seconds since trying to bootstrap */ + uint16_t dhcp_flags; /* flags for DHCP, unused for BOOTP */ + uint32_t dhcp_cip; /* client's IP */ + uint32_t dhcp_yip; /* your IP */ + uint32_t dhcp_sip; /* server's IP */ + uint32_t dhcp_gip; /* gateway IP */ + uint8_t dhcp_chaddr[16]; /* client hardware address, len is dhcp_hlen */ + char dhcp_sname[64]; /* server host name, null terminated string */ + char dhcp_file[128]; /* boot file name, null terminated string */ + uint32_t dhcp_magic; /* BOOTP magic header */ +#define DHCP_MAGIC 0x63825363 +#define LIBNET_BOOTP_MIN_LEN 0x12c +#define LIBNET_DHCP_PAD 0x00 +#define LIBNET_DHCP_SUBNETMASK 0x01 +#define LIBNET_DHCP_TIMEOFFSET 0x02 +#define LIBNET_DHCP_ROUTER 0x03 +#define LIBNET_DHCP_TIMESERVER 0x04 +#define LIBNET_DHCP_NAMESERVER 0x05 +#define LIBNET_DHCP_DNS 0x06 +#define LIBNET_DHCP_LOGSERV 0x07 +#define LIBNET_DHCP_COOKIESERV 0x08 +#define LIBNET_DHCP_LPRSERV 0x09 +#define LIBNET_DHCP_IMPSERV 0x0a +#define LIBNET_DHCP_RESSERV 0x0b +#define LIBNET_DHCP_HOSTNAME 0x0c +#define LIBNET_DHCP_BOOTFILESIZE 0x0d +#define LIBNET_DHCP_DUMPFILE 0x0e +#define LIBNET_DHCP_DOMAINNAME 0x0f +#define LIBNET_DHCP_SWAPSERV 0x10 +#define LIBNET_DHCP_ROOTPATH 0x11 +#define LIBNET_DHCP_EXTENPATH 0x12 +#define LIBNET_DHCP_IPFORWARD 0x13 +#define LIBNET_DHCP_SRCROUTE 0x14 +#define LIBNET_DHCP_POLICYFILTER 0x15 +#define LIBNET_DHCP_MAXASMSIZE 0x16 +#define LIBNET_DHCP_IPTTL 0x17 +#define LIBNET_DHCP_MTUTIMEOUT 0x18 +#define LIBNET_DHCP_MTUTABLE 0x19 +#define LIBNET_DHCP_MTUSIZE 0x1a +#define LIBNET_DHCP_LOCALSUBNETS 0x1b +#define LIBNET_DHCP_BROADCASTADDR 0x1c +#define LIBNET_DHCP_DOMASKDISCOV 0x1d +#define LIBNET_DHCP_MASKSUPPLY 0x1e +#define LIBNET_DHCP_DOROUTEDISC 0x1f +#define LIBNET_DHCP_ROUTERSOLICIT 0x20 +#define LIBNET_DHCP_STATICROUTE 0x21 +#define LIBNET_DHCP_TRAILERENCAP 0x22 +#define LIBNET_DHCP_ARPTIMEOUT 0x23 +#define LIBNET_DHCP_ETHERENCAP 0x24 +#define LIBNET_DHCP_TCPTTL 0x25 +#define LIBNET_DHCP_TCPKEEPALIVE 0x26 +#define LIBNET_DHCP_TCPALIVEGARBAGE 0x27 +#define LIBNET_DHCP_NISDOMAIN 0x28 +#define LIBNET_DHCP_NISSERVERS 0x29 +#define LIBNET_DHCP_NISTIMESERV 0x2a +#define LIBNET_DHCP_VENDSPECIFIC 0x2b +#define LIBNET_DHCP_NBNS 0x2c +#define LIBNET_DHCP_NBDD 0x2d +#define LIBNET_DHCP_NBTCPIP 0x2e +#define LIBNET_DHCP_NBTCPSCOPE 0x2f +#define LIBNET_DHCP_XFONT 0x30 +#define LIBNET_DHCP_XDISPLAYMGR 0x31 +#define LIBNET_DHCP_DISCOVERADDR 0x32 +#define LIBNET_DHCP_LEASETIME 0x33 +#define LIBNET_DHCP_OPTIONOVERLOAD 0x34 +#define LIBNET_DHCP_MESSAGETYPE 0x35 +#define LIBNET_DHCP_SERVIDENT 0x36 +#define LIBNET_DHCP_PARAMREQUEST 0x37 +#define LIBNET_DHCP_MESSAGE 0x38 +#define LIBNET_DHCP_MAXMSGSIZE 0x39 +#define LIBNET_DHCP_RENEWTIME 0x3a +#define LIBNET_DHCP_REBINDTIME 0x3b +#define LIBNET_DHCP_CLASSSID 0x3c +#define LIBNET_DHCP_CLIENTID 0x3d +#define LIBNET_DHCP_NISPLUSDOMAIN 0x40 +#define LIBNET_DHCP_NISPLUSSERVERS 0x41 +#define LIBNET_DHCP_MOBILEIPAGENT 0x44 +#define LIBNET_DHCP_SMTPSERVER 0x45 +#define LIBNET_DHCP_POP3SERVER 0x46 +#define LIBNET_DHCP_NNTPSERVER 0x47 +#define LIBNET_DHCP_WWWSERVER 0x48 +#define LIBNET_DHCP_FINGERSERVER 0x49 +#define LIBNET_DHCP_IRCSERVER 0x4a +#define LIBNET_DHCP_STSERVER 0x4b +#define LIBNET_DHCP_STDASERVER 0x4c +#define LIBNET_DHCP_END 0xff + +#define LIBNET_DHCP_MSGDISCOVER 0x01 +#define LIBNET_DHCP_MSGOFFER 0x02 +#define LIBNET_DHCP_MSGREQUEST 0x03 +#define LIBNET_DHCP_MSGDECLINE 0x04 +#define LIBNET_DHCP_MSGACK 0x05 +#define LIBNET_DHCP_MSGNACK 0x06 +#define LIBNET_DHCP_MSGRELEASE 0x07 +#define LIBNET_DHCP_MSGINFORM 0x08 +}; + + +/* this little guy got left out in the cold */ +#define LIBNET_DNS_H LIBNET_UDP_DNSV4_H +/* + * Base DNSv4 header + * Domain Name System + * Base header size: 12/14 bytes + */ +struct libnet_dnsv4_hdr +{ + uint16_t h_len; /* length of the packet - only used with TCP */ + uint16_t id; /* DNS packet ID */ + uint16_t flags; /* DNS flags */ + uint16_t num_q; /* Number of questions */ + uint16_t num_answ_rr; /* Number of answer resource records */ + uint16_t num_auth_rr; /* Number of authority resource records */ + uint16_t num_addi_rr; /* Number of additional resource records */ +}; + +#define LIBNET_DNS_H LIBNET_UDP_DNSV4_H +struct libnet_dnsv4udp_hdr +{ + uint16_t id; /* DNS packet ID */ + uint16_t flags; /* DNS flags */ + uint16_t num_q; /* Number of questions */ + uint16_t num_answ_rr; /* Number of answer resource records */ + uint16_t num_auth_rr; /* Number of authority resource records */ + uint16_t num_addi_rr; /* Number of additional resource records */ +}; + +/* + * Ethernet II header + * Static header size: 14 bytes + */ +struct libnet_ethernet_hdr +{ + uint8_t ether_dhost[ETHER_ADDR_LEN];/* destination ethernet address */ + uint8_t ether_shost[ETHER_ADDR_LEN];/* source ethernet address */ + uint16_t ether_type; /* protocol */ +}; + +#ifndef ETHERTYPE_PUP +#define ETHERTYPE_PUP 0x0200 /* PUP protocol */ +#endif +#ifndef ETHERTYPE_IP +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#endif +#ifndef ETHERTYPE_IPV6 +#define ETHERTYPE_IPV6 0x86dd /* IPv6 protocol */ +#endif +#ifndef ETHERTYPE_ARP +#define ETHERTYPE_ARP 0x0806 /* addr. resolution protocol */ +#endif +#ifndef ETHERTYPE_REVARP +#define ETHERTYPE_REVARP 0x8035 /* reverse addr. resolution protocol */ +#endif +#ifndef ETHERTYPE_VLAN +#define ETHERTYPE_VLAN 0x8100 /* IEEE 802.1Q VLAN tagging */ +#endif +#ifndef ETHERTYPE_EAP +#define ETHERTYPE_EAP 0x888e /* IEEE 802.1X EAP authentication */ +#endif +#ifndef ETHERTYPE_MPLS +#define ETHERTYPE_MPLS 0x8847 /* MPLS */ +#endif +#ifndef ETHERTYPE_LOOPBACK +#define ETHERTYPE_LOOPBACK 0x9000 /* used to test interfaces */ +#endif + +struct libnet_ether_addr +{ + uint8_t ether_addr_octet[6]; /* Ethernet address */ +}; + +/* + * Fiber Distributed Data Interface header + * + * Static header size: 21 bytes (LLC and 48-bit address addr only) + * + * Note: Organization field is 3 bytes which throws off the + * alignment of type. Therefore fddi_type (19 bytes in) + * is specified as two uint8_ts. + */ +struct libnet_fddi_hdr +{ + uint8_t fddi_frame_control; /* Class/Format/Priority */ +#define LIBNET_FDDI_LLC_FRAME 0x10 +#define LIBNET_FDDI_48BIT_ADDR 0x40 +#define LIBNET_FDDI_FC_REQD LIBNET_FDDI_LLC_FRAME | LIBNET_FDDI_48BIT_ADDR + uint8_t fddi_dhost[FDDI_ADDR_LEN]; /* destination fddi address */ + uint8_t fddi_shost[FDDI_ADDR_LEN]; /* source fddi address */ + uint8_t fddi_llc_dsap; /* DSAP */ + uint8_t fddi_llc_ssap; /* SSAP */ + uint8_t fddi_llc_control_field; /* Class/Format/Priority */ + uint8_t fddi_llc_org_code[LIBNET_ORG_CODE_SIZE]; /* Organization Code 3-bytes */ + uint8_t fddi_type; /* Protocol Type */ + uint8_t fddi_type1; /* see note above. */ +#define FDDI_TYPE_IP 0x0800 /* IP protocol */ +#define FDDI_TYPE_ARP 0x0806 /* addr. resolution protocol */ +#define FDDI_TYPE_REVARP 0x8035 /* reverse addr. resolution protocol */ +}; + + +struct libnet_fddi_addr +{ + uint8_t fddi_addr_octet[6]; /* FDDI address */ +}; + + +/* + * GRE header - RFC 1701 & 2637 + * Generic Routing Encapsulation (GRE) + * Base header size: 4 bytes + */ +struct libnet_gre_hdr +{ + uint16_t flags_ver; +#define GRE_CSUM 0x8000 +#define GRE_ROUTING 0x4000 +#define GRE_KEY 0x2000 +#define GRE_SEQ 0x1000 +#define GRE_STRICT 0x0800 +#define GRE_REC 0x0700 +#define GRE_ACK 0x0080 + +#define GRE_FLAGS_MASK 0x00F8 +#define GRE_VERSION_MASK 0x0007 + +#define GRE_VERSION_0 0x0000 +#define GRE_VERSION_1 0x0001 + + uint16_t type; +#define GRE_SNA 0x0004 +#define GRE_OSI_NETWORK_LAYER 0x00FE +#define GRE_PUP 0x0200 +#define GRE_XNS 0x0600 +#define GRE_IP 0x0800 +#define GRE_CHAOS 0x0804 +#define GRE_RFC_826_ARP 0x0806 +#define GRE_FRAME_RELAY_ARP 0x0808 +#define GRE_VINES 0x0BAD +#define GRE_VINES_ECHO 0x0BAE +#define GRE_VINES_LOOPBACK 0x0BAF +#define GRE_DECNET 0x6003 +#define GRE_TRANSPARENT_ETHERNET_BRIDGING 0x6558 +#define GRE_RAW_FRAME_RELAY 0x6559 +#define GRE_APOLLO_DOMAIN 0x8019 +#define GRE_ETHERTALK 0x809B +#define GRE_NOVELL_IPX 0x8137 +#define GRE_RFC_1144_TCP_IP_COMPRESSION 0x876B +#define GRE_IP_AUTONOMOUS_SYSTEMS 0x876C +#define GRE_SECURE_DATA 0x876D +#define GRE_PPP 0x880b /* taken from RFC 2637 */ + + union { + struct { + uint16_t sum; /* optional */ + uint16_t offset; /* optional */ + uint32_t key; /* optional */ + uint32_t seq; /* optional */ + } _gre; + + struct { + uint16_t payload_s; /* optional */ + uint16_t callID; /* optional */ + uint32_t seq; /* optional */ + uint32_t ack; /* optional */ + } _egre; + }_data; + +#define gre_sum _data._gre.sum +#define gre_offset _data._gre.offset +#define gre_key _data._gre.key +#define gre_seq _data._gre.seq + +#define egre_payload_s _data._egre.payload_s +#define egre_callID _data._egre.callID +#define egre_seq _data._egre.seq +#define egre_ack _data._egre.ack +}; + + +#ifndef IPPROTO_GRE +#define IPPROTO_GRE 47 +#endif + +/* + * Source Route Entries (SRE) + * This is used for GRE as the Routing field is a list of SREs - RFC 1701 + * Base header size: 4 bytes + */ +struct libnet_gre_sre_hdr +{ + uint16_t af; /* address familly */ + uint8_t sre_offset; + uint8_t sre_length; + uint8_t *routing; +}; + + +/* + * IPv4 header + * Internet Protocol, version 4 + * Static header size: 20 bytes + */ +struct libnet_ipv4_hdr +{ +#if (LIBNET_LIL_ENDIAN) + uint8_t ip_hl:4, /* header length */ + ip_v:4; /* version */ +#endif +#if (LIBNET_BIG_ENDIAN) + uint8_t ip_v:4, /* version */ + ip_hl:4; /* header length */ +#endif + uint8_t ip_tos; /* type of service */ +#ifndef IPTOS_LOWDELAY +#define IPTOS_LOWDELAY 0x10 +#endif +#ifndef IPTOS_THROUGHPUT +#define IPTOS_THROUGHPUT 0x08 +#endif +#ifndef IPTOS_RELIABILITY +#define IPTOS_RELIABILITY 0x04 +#endif +#ifndef IPTOS_LOWCOST +#define IPTOS_LOWCOST 0x02 +#endif + uint16_t ip_len; /* total length */ + uint16_t ip_id; /* identification */ + uint16_t ip_off; +#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 + uint8_t ip_ttl; /* time to live */ + uint8_t ip_p; /* protocol */ + uint16_t ip_sum; /* checksum */ + struct in_addr ip_src, ip_dst; /* source and dest address */ +}; + +/* + * IP options + */ +#ifndef IPOPT_EOL +#define IPOPT_EOL 0 /* end of option list */ +#endif +#ifndef IPOPT_NOP +#define IPOPT_NOP 1 /* no operation */ +#endif +#ifndef IPOPT_RR +#define IPOPT_RR 7 /* record packet route */ +#endif +#ifndef IPOPT_TS +#define IPOPT_TS 68 /* timestamp */ +#endif +#ifndef IPOPT_SECURITY +#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ +#endif +#ifndef IPOPT_LSRR +#define IPOPT_LSRR 131 /* loose source route */ +#endif +#ifndef IPOPT_SATID +#define IPOPT_SATID 136 /* satnet id */ +#endif +#ifndef IPOPT_SSRR +#define IPOPT_SSRR 137 /* strict source route */ +#endif + +/* + * IPv6 address + */ +struct libnet_in6_addr +{ + union + { + uint8_t __u6_addr8[16]; + uint16_t __u6_addr16[8]; + uint32_t __u6_addr32[4]; + } __u6_addr; /* 128-bit IP6 address */ +}; +#define libnet_s6_addr __u6_addr.__u6_addr8 + +/* + * IPv6 header + * Internet Protocol, version 6 + * Static header size: 40 bytes + */ +struct libnet_ipv6_hdr +{ + uint8_t ip_flags[4]; /* version, traffic class, flow label */ + uint16_t ip_len; /* total length */ + uint8_t ip_nh; /* next header */ + uint8_t ip_hl; /* hop limit */ + struct libnet_in6_addr ip_src, ip_dst; /* source and dest address */ +}; + +/* + * IPv6 frag header + * Internet Protocol, version 6 + * Static header size: 8 bytes + */ +#define LIBNET_IPV6_NH_FRAGMENT 44 +struct libnet_ipv6_frag_hdr +{ + uint8_t ip_nh; /* next header */ + uint8_t ip_reserved; /* reserved */ + uint16_t ip_frag; /* fragmentation stuff */ + uint32_t ip_id; /* id */ +}; + +/* + * IPv6 routing header + * Internet Protocol, version 6 + * Base header size: 4 bytes + */ +#define LIBNET_IPV6_NH_ROUTING 43 +struct libnet_ipv6_routing_hdr +{ + uint8_t ip_nh; /* next header */ + uint8_t ip_len; /* length of header in 8 octet units (sans 1st) */ + uint8_t ip_rtype; /* routing type */ + uint8_t ip_segments; /* segments left */ + /* routing information allocated dynamically */ +}; + +/* + * IPv6 destination options header + * Internet Protocol, version 6 + * Base header size: 2 bytes + */ +#define LIBNET_IPV6_NH_DESTOPTS 60 +struct libnet_ipv6_destopts_hdr +{ + uint8_t ip_nh; /* next header */ + uint8_t ip_len; /* length of header in 8 octet units (sans 1st) */ + /* destination options information allocated dynamically */ +}; + +/* + * IPv6 hop by hop options header + * Internet Protocol, version 6 + * Base header size: 2 bytes + */ +#define LIBNET_IPV6_NH_HBH 0 +struct libnet_ipv6_hbhopts_hdr +{ + uint8_t ip_nh; /* next header */ + uint8_t ip_len; /* length of header in 8 octet units (sans 1st) */ + /* destination options information allocated dynamically */ +}; + +/* + * ICMP6 header + * Internet Control Message Protocol v6 + * Base header size: 4 bytes + */ +#ifndef IPPROTO_ICMPV6 +#define IPPROTO_ICMPV6 58 +#endif +struct libnet_icmpv6_hdr +{ + uint8_t icmp_type; /* ICMP type */ +/* Don't define if has defined them. */ +#ifndef ICMP6_ECHO_REQUEST +#define ICMP6_ECHO_REQUEST 128 +#endif +#ifndef ICMP6_ECHO_REPLY +#define ICMP6_ECHO_REPLY 129 +#endif +#ifndef ICMP6_DST_UNREACH +#define ICMP6_DST_UNREACH 1 +#endif +#ifndef ICMP6_PACKET_TOO_BIG +#define ICMP6_PACKET_TOO_BIG 2 +#endif +#ifndef ICMP6_TIME_EXCEEDED +#define ICMP6_TIME_EXCEEDED 3 +#endif +#ifndef ICMP6_PARAM_PROB +#define ICMP6_PARAM_PROB 4 +#endif + +#ifndef ND_ROUTER_SOLICIT +#define ND_ROUTER_SOLICIT 133 +#endif +#ifndef ND_ROUTER_ADVERT +#define ND_ROUTER_ADVERT 134 +#endif +#ifndef ND_NEIGHBOR_SOLICIT +#define ND_NEIGHBOR_SOLICIT 135 +#endif +#ifndef ND_NEIGHBOR_ADVERT +#define ND_NEIGHBOR_ADVERT 136 +#endif + + uint8_t icmp_code; /* ICMP code */ +#ifndef ICMP6_DST_UNREACH_NOROUTE +#define ICMP6_DST_UNREACH_NOROUTE 0 +#endif +#ifndef ICMP6_DST_UNREACH_ADMIN +#define ICMP6_DST_UNREACH_ADMIN 1 +#endif +#ifndef ICMP6_DST_UNREACH_BEYONDSCOPE +#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 +#endif +#ifndef ICMP6_DST_UNREACH_ADDR +#define ICMP6_DST_UNREACH_ADDR 3 +#endif +#ifndef ICMP6_DST_UNREACH_NOPORT +#define ICMP6_DST_UNREACH_NOPORT 4 +#endif + uint16_t icmp_sum; /* ICMP Checksum */ + + /* This is confusing: id/seq are used only for echo req/reply, but must + * exist in struct for backwards compatibility. */ + uint16_t id; /* ICMP id (unused, for backwards compatibility) */ + uint16_t seq; /* ICMP sequence number (unused, for backwards compatibility) */ + + /* Non-standard names, for libnet backwards compatibility, don't use. */ + /* ipproto: */ +#define IPPROTO_ICMP6 58 + /* types: */ +#define ICMP6_ECHO 128 +#define ICMP6_ECHOREPLY 129 +#define ICMP6_UNREACH 1 +#define ICMP6_PKTTOOBIG 2 +#define ICMP6_TIMXCEED 3 +#define ICMP6_PARAMPROB 4 + /* codes: */ +#define ICMP6_NOROUTE 0 +#define ICMP6_ADM_PROHIBITED 1 +#define ICMP6_NOT_NEIGHBOUR 2 +#define ICMP6_ADDR_UNREACH 3 +#define ICMP6_PORT_UNREACH 4 +}; + +/* All of this stuff follows base ICMPv6 header */ + +struct libnet_icmpv6_unreach { + uint32_t unused; +}; + +struct libnet_icmpv6_echo { + uint16_t id; + uint16_t seq; +}; + +struct libnet_icmpv6_ndp_nsol { + uint32_t reserved; + struct libnet_in6_addr target_addr; +}; + +struct libnet_icmpv6_ndp_nadv { + uint32_t flags; +#ifndef ND_NA_FLAG_ROUTER +#define ND_NA_FLAG_ROUTER 0x80000000 +#endif +#ifndef ND_NA_FLAG_SOLICITED +#define ND_NA_FLAG_SOLICITED 0x40000000 +#endif +#ifndef ND_NA_FLAG_OVERRIDE +#define ND_NA_FLAG_OVERRIDE 0x20000000 +#endif + struct libnet_in6_addr target_addr; +}; + +struct libnet_icmpv6_ndp_opt { + uint8_t type; +#ifndef ND_OPT_SOURCE_LINKADDR +#define ND_OPT_SOURCE_LINKADDR 1 +#endif +#ifndef ND_OPT_TARGET_LINKADDR +#define ND_OPT_TARGET_LINKADDR 2 +#endif +#ifndef ND_OPT_PREFIX_INFORMATION +#define ND_OPT_PREFIX_INFORMATION 3 +#endif +#ifndef ND_OPT_REDIRECTED_HEADER +#define ND_OPT_REDIRECTED_HEADER 4 +#endif +#ifndef ND_OPT_MTU +#define ND_OPT_MTU 5 +#endif +#ifndef ND_OPT_RTR_ADV_INTERVAL +#define ND_OPT_RTR_ADV_INTERVAL 7 +#endif +#ifndef ND_OPT_HOME_AGENT_INFO +#define ND_OPT_HOME_AGENT_INFO 8 +#endif + uint8_t len; +}; + + +/* + * ICMP header + * Internet Control Message Protocol + * Base header size: 4 bytes + */ +struct libnet_icmpv4_hdr +{ + uint8_t icmp_type; /* ICMP type */ +#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 + uint8_t icmp_code; /* ICMP code */ +#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 + + uint16_t icmp_sum; /* ICMP Checksum */ + + union + { + struct + { + uint16_t id; /* ICMP id */ + uint16_t seq;/* ICMP sequence number */ + } echo; + + /* TODO this hack conflicts with the system headers, which is why we + * undef what they do, and it also damages dnet/dumbnet's headers if + * they are included after ours. Fixing will break API, though, so + * we leave it for now. + */ +#undef icmp_id +#undef icmp_seq +#define icmp_id hun.echo.id +#define icmp_seq hun.echo.seq + + uint32_t gateway; /* gateway host */ + struct + { + uint16_t pad;/* padding */ + uint16_t mtu;/* MTU size */ + } frag; + } hun; + union + { + struct + { + uint32_t its_otime; + uint32_t its_rtime; + uint32_t its_ttime; + } ts; + struct + { + struct libnet_ipv4_hdr idi_ip; + /* options and then 64 bits of data */ + } ip; + uint32_t mask; + int8_t 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; +}; + + +/* + * IGMP header + * Internet Group Message Protocol + * Static header size: 8 bytes + */ +struct libnet_igmp_hdr +{ + uint8_t igmp_type; /* IGMP type */ +#ifndef IGMP_MEMBERSHIP_QUERY +#define IGMP_MEMBERSHIP_QUERY 0x11 /* membership query */ +#endif +#ifndef IGMP_V1_MEMBERSHIP_REPORT +#define IGMP_V1_MEMBERSHIP_REPORT 0x12 /* Ver. 1 membership report */ +#endif +#ifndef IGMP_V2_MEMBERSHIP_REPORT +#define IGMP_V2_MEMBERSHIP_REPORT 0x16 /* Ver. 2 membership report */ +#endif +#ifndef IGMP_LEAVE_GROUP +#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */ +#endif + uint8_t igmp_code; /* IGMP reserved field (0), mistakenly called 'code' in early libnet versions */ + uint16_t igmp_sum; /* IGMP checksum */ + struct in_addr igmp_group;/* IGMP host IP */ +}; + + +/* + * IPSEC header + * Internet Protocol Security Protocol + * Encapsulating Security Payload Header Static header size: 12 bytes + * Encapsulating Security Payload Footer Base header size: 2 bytes + * Authentication Header Static Size: 16 bytes + */ +#ifndef IPPROTO_ESP +#define IPPROTO_ESP 50 /* not everyone's got this */ +#endif +struct libnet_esp_hdr +{ + uint32_t esp_spi; /* security parameter index */ + uint32_t esp_seq; /* ESP sequence number */ + uint32_t esp_iv; /* initialization vector */ +}; + +struct libnet_esp_ftr +{ + uint8_t esp_pad_len; /* padding length */ + uint8_t esp_nh; /* next header pointer */ + int8_t *esp_auth; /* authentication data */ +}; + +#ifndef IPPROTO_AH +#define IPPROTO_AH 51 /* not everyone's got this */ +#endif +struct libnet_ah_hdr +{ + uint8_t ah_nh; /* next header */ + uint8_t ah_len; /* payload length */ + uint16_t ah_res; /* reserved */ + uint32_t ah_spi; /* security parameter index */ + uint32_t ah_seq; /* AH sequence number */ + uint32_t ah_auth; /* authentication data */ +}; + + +/* + * For checksum stuff -- IANA says 135-254 is "unassigned" as of 12.2001. + * Let's hope this one stays that way for a while! + */ +#define LIBNET_PROTO_ISL 201 +/* + * ISL header + * Cisco Inter-Switch Link + * Static header size: 26 bytes + */ +struct libnet_isl_hdr +{ + uint8_t isl_dhost[5]; /* destination address "01:00:0c:00:00" */ +#if (LIBNET_LIL_ENDIAN) + uint8_t isl_type:4, /* type of frame */ + isl_user:4; /* user defined bits */ +#endif +#if (LIBNET_BIG_ENDIAN) + uint8_t isl_user:4, /* user defined bits */ + isl_type:4; /* type of frame */ +#endif + uint8_t isl_shost[6]; /* source address */ + uint16_t isl_len; /* total length of packet - 18 bytes */ + uint8_t isl_snap[6]; /* 0xaaaa03 + vendor code */ + uint16_t isl_vid; /* 15 bit VLAN ID, 1 bit BPDU / CDP indicator */ + uint16_t isl_index; /* port index */ + uint16_t isl_reserved; /* used for FDDI and token ring */ + /* ethernet frame and 4 byte isl crc */ +}; + +#ifndef IPPROTO_OSPF +#define IPPROTO_OSPF 89 /* not everyone's got this */ +#endif +#define IPPROTO_OSPF_LSA 890 /* made this up. Hope it's unused */ +#define LIBNET_MODX 4102 /* used in LSA checksum */ + +/* + * Options used in multiple OSPF packets + * More info can be found in section A.2 of RFC 2328. + */ +#define LIBNET_OPT_EBIT 0x02 /* describes the way AS-external-LSAs are flooded */ +#define LIBNET_OPT_MCBIT 0x04 /* whether or not IP multicast dgrams are fwdd */ +#define LIBNET_OPT_NPBIT 0x08 /* describes handling of type-7 LSAs */ +#define LIBNET_OPT_EABIT 0x10 /* rtr's willingness to send/recv EA-LSAs */ +#define LIBNET_OPT_DCBIT 0x20 /* describes handling of demand circuits */ + + +/* + * MPLS header + * Multi-Protocol Label Switching + * Static header size: 4 bytes + */ +struct libnet_mpls_hdr +{ + uint32_t mpls_les; /* 20 bits label, 3 bits exp, 1 bit bos, ttl */ +#define LIBNET_MPLS_BOS_ON 1 +#define LIBNET_MPLS_BOS_OFF 0 +}; + +/* + * NTP header + * Network Time Protocol + * Static header size: 48 bytes + */ +struct libnet_ntp_hdr_l_fp /* int32_t floating point (64-bit) */ +{ + uint32_t integer; /* integer */ + uint32_t fraction; /* fraction */ +}; + +struct libnet_ntp_hdr_s_fp /* int16_t floating point (32-bit) */ +{ + uint16_t integer; /* integer */ + uint16_t fraction; /* fraction */ +}; + + +struct libnet_ntp_hdr +{ + uint8_t ntp_li_vn_mode; /* leap indicator, version, mode */ +#define LIBNET_NTP_LI_NW 0x0 /* no warning */ +#define LIBNET_NTP_LI_AS 0x1 /* last minute has 61 seconds */ +#define LIBNET_NTP_LI_DS 0x2 /* last minute has 59 seconds */ +#define LIBNET_NTP_LI_AC 0x3 /* alarm condition */ + +#define LIBNET_NTP_VN_2 0x2 /* version 2 */ +#define LIBNET_NTP_VN_3 0x3 /* version 3 */ +#define LIBNET_NTP_VN_4 0x4 /* version 4 */ + +#define LIBNET_NTP_MODE_R 0x0 /* reserved */ +#define LIBNET_NTP_MODE_A 0x1 /* symmetric active */ +#define LIBNET_NTP_MODE_P 0x2 /* symmetric passive */ +#define LIBNET_NTP_MODE_C 0x3 /* client */ +#define LIBNET_NTP_MODE_S 0x4 /* server */ +#define LIBNET_NTP_MODE_B 0x5 /* broadcast */ +#define LIBNET_NTP_MODE_RC 0x6 /* reserved for NTP control message */ +#define LIBNET_NTP_MODE_RP 0x7 /* reserved for private use */ + uint8_t ntp_stratum; /* stratum */ +#define LIBNET_NTP_STRATUM_UNAVAIL 0x0 /* unspecified or unavailable */ +#define LIBNET_NTP_STRATUM_PRIMARY 0x1 /* primary reference (radio clock) */ + /* 2 - 15 is secondary */ + /* 16 - 255 is reserved */ + uint8_t ntp_poll; /* poll interval (should be 4 - 12) */ + uint8_t ntp_precision; /* local clock precision */ + struct libnet_ntp_hdr_s_fp ntp_delay; /* roundtrip delay */ + struct libnet_ntp_hdr_s_fp ntp_dispersion; /* nominal error */ + uint32_t ntp_reference_id; /* reference source id */ +#define LIBNET_NTP_REF_LOCAL 0x4c4f434c /* uncalibrated local clock */ +#define LIBNET_NTP_REF_PPS 0x50505300 /* atomic / pulse-per-second clock */ +#define LIBNET_NTP_REF_ACTS 0x41435453 /* NIST dialup modem */ +#define LIBNET_NTP_REF_USNO 0x55534e4f /* USNO modem service */ +#define LIBNET_NTP_REF_PTB 0x50544200 /* PTB (German) modem service */ +#define LIBNET_NTP_REF_TDF 0x54444600 /* Allouis (French) radio */ +#define LIBNET_NTP_REF_DCF 0x44434600 /* Mainflingen (German) radio */ +#define LIBNET_NTP_REF_MSF 0x4d534600 /* Rugby (UK) radio */ +#define LIBNET_NTP_REF_WWV 0x57575600 /* Ft Collins (US) radio */ +#define LIBNET_NTP_REF_WWVB 0x57575642 /* Boulder (US) radio */ +#define LIBNET_NTP_REF_WWVH 0x57575648 /* Kaui Hawaii (US) radio */ +#define LIBNET_NTP_REF_CHU 0x43485500 /* Ottaha (Canada) radio */ +#define LIBNET_NTP_REF_LORC 0x4c4f5243 /* LORAN-C radionavigation */ +#define LIBNET_NTP_REF_OMEG 0x4f4d4547 /* OMEGA radionavigation */ +#define LIBNET_NTP_REF_GPS 0x47505300 /* global positioning system */ +#define LIBNET_NTP_REF_GOES 0x474f4553 /* geostationary orbit env satellite */ + struct libnet_ntp_hdr_l_fp ntp_ref_ts; /* reference timestamp */ + struct libnet_ntp_hdr_l_fp ntp_orig_ts; /* originate timestamp */ + struct libnet_ntp_hdr_l_fp ntp_rec_ts; /* receive timestamp */ + struct libnet_ntp_hdr_l_fp ntp_xmt_ts; /* transmit timestamp */ +}; + + +/* + * OSPFv2 header + * Open Shortest Path First + * Static header size: 16 bytes + */ +struct libnet_ospf_hdr +{ + uint8_t ospf_v; /* version */ +#define OSPFVERSION 2 + uint8_t ospf_type; /* type */ +#define LIBNET_OSPF_UMD 0 /* UMd monitoring packet */ +#define LIBNET_OSPF_HELLO 1 /* HELLO packet */ +#define LIBNET_OSPF_DBD 2 /* dataBase description packet */ +#define LIBNET_OSPF_LSR 3 /* link state request packet */ +#define LIBNET_OSPF_LSU 4 /* link state Update Packet */ +#define LIBNET_OSPF_LSA 5 /* link state acknowledgement packet */ + uint16_t ospf_len; /* length */ + struct in_addr ospf_rtr_id; /* source router ID */ + struct in_addr ospf_area_id;/* roam ID */ + uint16_t ospf_sum; /* checksum */ + uint16_t ospf_auth_type; /* authentication type */ +#define LIBNET_OSPF_AUTH_NULL 0 /* null password */ +#define LIBNET_OSPF_AUTH_SIMPLE 1 /* simple, plaintext, 8 int8_t password */ +#define LIBNET_OSPF_AUTH_MD5 2 /* MD5 */ +}; + + +/* + * OSPF authentication header + * Open Shortest Path First + * Static header size: 8 bytes + */ +struct libnet_auth_hdr +{ + uint16_t ospf_auth_null; /* NULL */ + uint8_t ospf_auth_keyid; /* authentication key ID */ + uint8_t ospf_auth_len; /* auth data length */ + uint32_t ospf_auth_seq; /* cryptographic sequence number */ +}; + + +/* + * OSPF hello header + * Open Shortest Path First + * Static header size: 28 bytes + */ +struct libnet_ospf_hello_hdr +{ + struct in_addr hello_nmask; /* netmask associated with the interface */ + uint16_t hello_intrvl; /* num of seconds between routers last packet */ + uint8_t hello_opts; /* Options for HELLO packets (look above) */ + uint8_t hello_rtr_pri; /* router's priority (if 0, can't be backup) */ + uint32_t hello_dead_intvl; /* # of secs a router is silent till deemed down */ + struct in_addr hello_des_rtr; /* Designated router on the network */ + struct in_addr hello_bkup_rtr; /* Backup router */ + struct in_addr hello_nbr; /* neighbor router, memcpy more as needed */ +}; + + +/* + * Database Description header. + */ +struct libnet_dbd_hdr +{ + uint16_t dbd_mtu_len; /* max length of IP dgram that this 'if' can use */ + uint8_t dbd_opts; /* DBD packet options (from above) */ + uint8_t dbd_type; /* type of exchange occurring */ +#define LIBNET_DBD_IBI 0x01 /* init */ +#define LIBNET_DBD_MBIT 0x02 /* more DBD packets are to come */ +#define LIBNET_DBD_MSBIT 0x04 /* If 1, sender is the master in the exchange */ + uint32_t dbd_seq; /* DBD sequence number */ +}; + + +/* + * used for the LS type field in all LS* headers + */ +#define LIBNET_LS_TYPE_RTR 1 /* router-LSA */ +#define LIBNET_LS_TYPE_NET 2 /* network-LSA */ +#define LIBNET_LS_TYPE_IP 3 /* summary-LSA (IP Network) */ +#define LIBNET_LS_TYPE_ASBR 4 /* summary-LSA (ASBR) */ +#define LIBNET_LS_TYPE_ASEXT 5 /* AS-external-LSA */ + + +/* + * Link State Request header + */ +struct libnet_lsr_hdr +{ + uint32_t lsr_type; /* type of LS being requested */ + uint32_t lsr_lsid; /* link state ID */ + struct in_addr lsr_adrtr; /* advertising router (memcpy more as needed) */ +}; + + +/* + * Link State Update header + */ +struct libnet_lsu_hdr +{ + uint32_t lsu_num; /* number of LSAs that will be broadcasted */ +}; + + +/* + * Link State Acknowledgement header. + */ +struct libnet_lsa_hdr +{ + uint16_t lsa_age; /* time in seconds since the LSA was originated */ + uint8_t lsa_opts; /* look above for OPTS_* */ + uint8_t lsa_type; /* look below for LS_TYPE_* */ + uint32_t lsa_id; /* link State ID */ + struct in_addr lsa_adv; /* router ID of Advertising router */ + uint32_t lsa_seq; /* LSA sequence number to detect old/bad ones */ + uint16_t lsa_sum; /* "Fletcher Checksum" of all fields minus age */ + uint16_t lsa_len; /* length in bytes including the 20 byte header */ +}; + + +/* + * Router LSA data format + * + * Other stuff for TOS can be added for backward compatability, for this + * version, only OSPFv2 is being FULLY supported. + */ +struct libnet_rtr_lsa_hdr +{ + uint16_t rtr_flags; /* set to help describe packet */ +#define LIBNET_RTR_FLAGS_W 0x0100 /* W bit */ +#define LIBNET_RTR_FLAGS_E 0x0200 /* E bit */ +#define LIBNET_RTR_FLAGS_B 0x0400 /* B bit */ + uint16_t rtr_num; /* number of links within that packet */ + uint32_t rtr_link_id; /* describes link_data (look below) */ +#define LIBNET_LINK_ID_NBR_ID 1 /* Neighbors router ID, also can be 4 */ +#define LIBNET_LINK_ID_IP_DES 2 /* IP address of designated router */ +#define LIBNET_LINK_ID_SUB 3 /* IP subnet number */ + uint32_t rtr_link_data; /* Depending on link_id, info is here */ + uint8_t rtr_type; /* Description of router link */ +#define LIBNET_RTR_TYPE_PTP 1 /* Point-To-Point */ +#define LIBNET_RTR_TYPE_TRANS 2 /* Connection to a "transit network" */ +#define LIBNET_RTR_TYPE_STUB 3 /* Connectin to a "stub network" */ +#define RTR_TYPE_VRTL 4 /* connects to a "virtual link" */ + uint8_t rtr_tos_num; /* number of different TOS metrics for this link */ + uint16_t rtr_metric; /* the "cost" of using this link */ +}; + + +/* + * Network LSA data format. + */ +struct libnet_net_lsa_hdr +{ + struct in_addr net_nmask; /* Netmask for that network */ + uint32_t net_rtr_id; /* ID of router attached to that network */ +}; + + +/* + * Summary LSA data format. + */ +struct libnet_sum_lsa_hdr +{ + struct in_addr sum_nmask; /* Netmask of destination IP address */ + uint32_t sum_metric; /* Same as in rtr_lsa (&0xfff to use last 24bit */ + uint32_t sum_tos_metric; /* first 8bits are TOS, 24bits are TOS Metric */ +}; + + +/* + * AS External LSA data format. + * & 0xfff logic operator for as_metric to get last 24bits. + */ +struct libnet_as_lsa_hdr +{ + struct in_addr as_nmask; /* Netmask for advertised destination */ + uint32_t as_metric; /* May have to set E bit in first 8bits */ +#define LIBNET_AS_E_BIT_ON 0x80000000 /* as_metric */ + struct in_addr as_fwd_addr; /* Forwarding address */ + uint32_t as_rte_tag; /* External route tag */ +}; + + +/* + * Base RIP header + * Routing Information Protocol + * Base header size: 24 bytes + */ +struct libnet_rip_hdr +{ + uint8_t rip_cmd; /* RIP command */ +#define RIPCMD_REQUEST 1 /* want info */ +#define RIPCMD_RESPONSE 2 /* responding to request */ +#define RIPCMD_TRACEON 3 /* turn tracing on */ +#define RIPCMD_TRACEOFF 4 /* turn it off */ +#define RIPCMD_POLL 5 /* like request, but anyone answers */ +#define RIPCMD_POLLENTRY 6 /* like poll, but for entire entry */ +#define RIPCMD_MAX 7 /* ? command */ + uint8_t rip_ver; /* RIP version */ +#define RIPVER_0 0 +#define RIPVER_1 1 +#define RIPVER_2 2 + uint16_t rip_rd; /* Zero (v1) or Routing Domain (v2) */ + uint16_t rip_af; /* Address family */ + uint16_t rip_rt; /* Zero (v1) or Route Tag (v2) */ + uint32_t rip_addr; /* IP address */ + uint32_t rip_mask; /* Zero (v1) or Subnet Mask (v2) */ + uint32_t rip_next_hop; /* Zero (v1) or Next hop IP address (v2) */ + uint32_t rip_metric; /* Metric */ +}; + +/* + * RPC headers + * Remote Procedure Call + */ +#define LIBNET_RPC_CALL 0 +#define LIBNET_RPC_REPLY 1 +#define LIBNET_RPC_VERS 2 +#define LIBNET_RPC_LAST_FRAG 0x80000000 + +/* + * Portmap defines + */ +#define LIBNET_PMAP_PROGRAM 100000 +#define LIBNET_PMAP_PROC_NULL 0 +#define LIBNET_PMAP_PROC_SET 1 +#define LIBNET_PMAP_PROC_UNSET 2 +#define LIBNET_PMAP_PROC_GETADDR 3 +#define LIBNET_PMAP_PROC_DUMP 4 +#define LIBNET_PMAP_PROC_CALLIT 5 +#define LIBNET_PMAP_PROC_BCAST 5 /* Not a typo */ +#define LIBNET_PMAP_PROC_GETTIME 6 +#define LIBNET_PMAP_PROC_UADDR2TADDR 7 +#define LIBNET_PMAP_PROC_TADDR2UADDR 8 +#define LIBNET_PMAP_PROC_GETVERSADDR 9 +#define LIBNET_PMAP_PROC_INDIRECT 10 +#define LIBNET_PMAP_PROC_GETADDRLIST 11 +#define LIBNET_PMAP_PROC_GETSTAT 12 + +/* There will be more to add... */ + +struct libnet_rpc_opaque_auth +{ + uint32_t rpc_auth_flavor; + uint32_t rpc_auth_length; +#if 0 + uint8_t *rpc_auth_data; +#endif +}; + +struct libnet_rpc_call +{ + uint32_t rpc_rpcvers; /* RPC version - must be 2 */ + uint32_t rpc_prognum; /* Program Number */ + uint32_t rpc_vers; /* Program Version */ + uint32_t rpc_procedure; /* RPC procedure */ + struct libnet_rpc_opaque_auth rpc_credentials; + struct libnet_rpc_opaque_auth rpc_verifier; +}; + +struct libnet_rpc_call_hdr +{ + uint32_t rpc_xid; /* xid (transaction identifier) */ + uint32_t rpc_type; + struct libnet_rpc_call rpc_call; +}; + +struct libnet_rpc_call_tcp_hdr +{ + uint32_t rpc_record_marking; /* used with byte stream protocols */ + struct libnet_rpc_call_hdr rpc_common; +}; + +/* + * STP configuration header + * Spanning Tree Protocol + * Static header size: 35 bytes + */ +struct libnet_stp_conf_hdr +{ + uint16_t stp_id; /* protocol id */ + uint8_t stp_version; /* protocol version */ + uint8_t stp_bpdu_type; /* bridge protocol data unit type */ + uint8_t stp_flags; /* control flags */ + uint8_t stp_rootid[8]; /* root id */ + uint32_t stp_rootpc; /* root path cost */ + uint8_t stp_bridgeid[8]; /* bridge id */ + uint16_t stp_portid; /* port id */ + uint16_t stp_mage; /* message age */ + uint16_t stp_maxage; /* max age */ + uint16_t stp_hellot; /* hello time */ + uint16_t stp_fdelay; /* forward delay */ +}; + + +/* + * STP topology change notification header + * Spanning Tree Protocol + * Static header size: 4 bytes + */ +struct libnet_stp_tcn_hdr +{ + uint16_t stp_id; /* protocol id */ + uint8_t stp_version; /* protocol version */ + uint8_t stp_bpdu_type; /* bridge protocol data unit type */ +}; + + +/* + * TCP header + * Transmission Control Protocol + * Static header size: 20 bytes + */ +struct libnet_tcp_hdr +{ + uint16_t th_sport; /* source port */ + uint16_t th_dport; /* destination port */ + uint32_t th_seq; /* sequence number */ + uint32_t th_ack; /* acknowledgement number */ +#if (LIBNET_LIL_ENDIAN) + uint8_t th_x2:4, /* (unused) */ + th_off:4; /* data offset */ +#endif +#if (LIBNET_BIG_ENDIAN) + uint8_t th_off:4, /* data offset */ + th_x2:4; /* (unused) */ +#endif + uint8_t th_flags; /* control flags */ +#ifndef TH_FIN +#define TH_FIN 0x01 /* finished send data */ +#endif +#ifndef TH_SYN +#define TH_SYN 0x02 /* synchronize sequence numbers */ +#endif +#ifndef TH_RST +#define TH_RST 0x04 /* reset the connection */ +#endif +#ifndef TH_PUSH +#define TH_PUSH 0x08 /* push data to the app layer */ +#endif +#ifndef TH_ACK +#define TH_ACK 0x10 /* acknowledge */ +#endif +#ifndef TH_URG +#define TH_URG 0x20 /* urgent! */ +#endif +#ifndef TH_ECE +#define TH_ECE 0x40 +#endif +#ifndef TH_CWR +#define TH_CWR 0x80 +#endif + uint16_t th_win; /* window */ + uint16_t th_sum; /* checksum */ + uint16_t th_urp; /* urgent pointer */ +}; + +/* + * Token Ring Header + */ +struct libnet_token_ring_hdr +{ + uint8_t token_ring_access_control; +#define LIBNET_TOKEN_RING_FRAME 0x10 + uint8_t token_ring_frame_control; +#define LIBNET_TOKEN_RING_LLC_FRAME 0x40 + uint8_t token_ring_dhost[TOKEN_RING_ADDR_LEN]; + uint8_t token_ring_shost[TOKEN_RING_ADDR_LEN]; + uint8_t token_ring_llc_dsap; + uint8_t token_ring_llc_ssap; + uint8_t token_ring_llc_control_field; + uint8_t token_ring_llc_org_code[LIBNET_ORG_CODE_SIZE]; + uint16_t token_ring_type; +#define TOKEN_RING_TYPE_IP 0x0800 /* IP protocol */ +#define TOKEN_RING_TYPE_ARP 0x0806 /* addr. resolution protocol */ +#define TOKEN_RING_TYPE_REVARP 0x8035 /* reverse addr. resolution protocol */ +}; + +struct libnet_token_ring_addr +{ + uint8_t token_ring_addr_octet[6]; /* Token Ring address */ +}; + +/* + * UDP header + * User Data Protocol + * Static header size: 8 bytes + */ +struct libnet_udp_hdr +{ + uint16_t uh_sport; /* source port */ + uint16_t uh_dport; /* destination port */ + uint16_t uh_ulen; /* length */ + uint16_t uh_sum; /* checksum */ +}; + +/* + * Sebek header + * Static header size: 48 bytes + */ +struct libnet_sebek_hdr +{ + uint32_t magic; /* identify packets that should be hidden */ + uint16_t version; /* protocol version, currently 1 */ +#define SEBEK_PROTO_VERSION 1 + uint16_t type; /* type of record (read data is type 0, write data is type 1) */ +#define SEBEK_TYPE_READ 0 /* Currently, only read is supported */ +#define SEBEK_TYPE_WRITE 1 + uint32_t counter; /* PDU counter used to identify when packet are lost */ + uint32_t time_sec; /* seconds since EPOCH according to the honeypot */ + uint32_t time_usec; /* residual microseconds */ + uint32_t pid; /* PID */ + uint32_t uid; /* UID */ + uint32_t fd; /* FD */ +#define SEBEK_CMD_LENGTH 12 + uint8_t cmd[SEBEK_CMD_LENGTH]; /* 12 first characters of the command */ + uint32_t length; /* length in bytes of the PDU's body */ +}; + + +/* + * VRRP header + * Virtual Router Redundancy Protocol + * Static header size: 8 bytes + */ +#ifndef IPPROTO_VRRP +#define IPPROTO_VRRP 112 /* not everyone's got this */ +#endif +struct libnet_vrrp_hdr +{ +#if (LIBNET_LIL_ENDIAN) + uint8_t vrrp_v:4, /* protocol version */ + vrrp_t:4; /* packet type */ +#endif +#if (LIBNET_BIG_ENDIAN) + uint8_t vrrp_t:4, /* packet type */ + vrrp_v:4; /* protocol version */ +#endif +#define LIBNET_VRRP_VERSION_01 0x1 +#define LIBNET_VRRP_VERSION_02 0x2 +#define LIBNET_VRRP_TYPE_ADVERT 0x1 + uint8_t vrrp_vrouter_id; /* virtual router id */ + uint8_t vrrp_priority; /* priority */ + uint8_t vrrp_ip_count; /* number of IP addresses */ + uint8_t vrrp_auth_type; /* authorization type */ +#define LIBNET_VRRP_AUTH_NONE 0x1 +#define LIBNET_VRRP_AUTH_PASSWD 0x2 +#define LIBNET_VRRP_AUTH_IPAH 0x3 + uint8_t vrrp_advert_int; /* advertisement interval */ + uint16_t vrrp_sum; /* checksum */ + /* additional addresses */ + /* authentication info */ +}; + + +/* + * HSRP header + * Static header size: 20 bytes + */ +struct libnet_hsrp_hdr +{ +#define LIBNET_HSRP_VERSION 0x0 + uint8_t version; /* Version of the HSRP messages */ +#define LIBNET_HSRP_TYPE_HELLO 0x0 +#define LIBNET_HSRP_TYPE_COUP 0x1 +#define LIBNET_HSRP_TYPE_RESIGN 0x2 + uint8_t opcode; /* Type of message */ +#define LIBNET_HSRP_STATE_INITIAL 0x0 +#define LIBNET_HSRP_STATE_LEARN 0x1 +#define LIBNET_HSRP_STATE_LISTEN 0x2 +#define LIBNET_HSRP_STATE_SPEAK 0x4 +#define LIBNET_HSRP_STATE_STANDBY 0x8 +#define LIBNET_HSRP_STATE_ACTIVE 0x10 + uint8_t state; /* Current state of the router */ + uint8_t hello_time; /* Period in seconds between hello messages */ + uint8_t hold_time; /* Seconds that the current hello message is valid */ + uint8_t priority; /* Priority for the election proccess */ + uint8_t group; /* Standby group */ + uint8_t reserved; /* Reserved field */ +#define HSRP_AUTHDATA_LENGTH 8 + uint8_t authdata[HSRP_AUTHDATA_LENGTH]; /* Password */ + uint32_t virtual_ip; /* Virtual IP address */ +}; + +#endif /* __LIBNET_HEADERS_H */ + +/** + * Local Variables: + * indent-tabs-mode: nil + * c-file-style: "stroustrup" + * End: + */ diff --git a/source/tools/detect/net_diag/tcpping/include/libnet/libnet-macros.h b/source/tools/detect/net_diag/tcpping/include/libnet/libnet-macros.h new file mode 100644 index 0000000000000000000000000000000000000000..1618424aaffa3942e40c7866350b387baa0871cb --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/include/libnet/libnet-macros.h @@ -0,0 +1,207 @@ +/* + * $Id: libnet-macros.h,v 1.7 2004/04/13 17:32:28 mike Exp $ + * + * libnet-macros.h - Network routine library macro header file + * + * Copyright (c) 1998 - 2004 Mike D. Schiffman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef __LIBNET_MACROS_H +#define __LIBNET_MACROS_H +/** + * @file libnet-macros.h + * @brief libnet macros and symbolic constants + */ + + +/** + * Used for libnet's name resolution functions, specifies that no DNS lookups + * should be performed and the IP address should be kept in numeric form. + */ +#define LIBNET_DONT_RESOLVE 0 + +/** + * Used for libnet's name resolution functions, specifies that a DNS lookup + * can be performed if needed to resolve the IP address to a canonical form. + */ +#define LIBNET_RESOLVE 1 + +/** + * Used several places, to specify "on" or "one" + */ +#define LIBNET_ON 0 + +/** + * Used several places, to specify "on" or "one" + */ +#define LIBNET_OFF 1 + +/** + * IPv6 error code + */ +#ifndef IN6ADDR_ERROR_INIT +#define IN6ADDR_ERROR_INIT { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff } } } +#endif + +/** + * Used for libnet_get_prand() to specify function disposition + */ +#define LIBNET_PR2 0 +#define LIBNET_PR8 1 +#define LIBNET_PR16 2 +#define LIBNET_PRu16 3 +#define LIBNET_PR32 4 +#define LIBNET_PRu32 5 +#define LIBNET_PRAND_MAX 0xffffffff + +/** + * The biggest an IP packet can be -- 65,535 bytes. + */ +#define LIBNET_MAX_PACKET 0xffff +#ifndef IP_MAXPACKET +#define IP_MAXPACKET 0xffff +#endif + + +/* ethernet addresses are 6 octets long */ +#ifndef ETHER_ADDR_LEN +#define ETHER_ADDR_LEN 0x6 +#endif + +/* FDDI addresses are 6 octets long */ +#ifndef FDDI_ADDR_LEN +#define FDDI_ADDR_LEN 0x6 +#endif + +/* token ring addresses are 6 octets long */ +#ifndef TOKEN_RING_ADDR_LEN +#define TOKEN_RING_ADDR_LEN 0x6 +#endif + +/* LLC Organization Code is 3 bytes long */ +#define LIBNET_ORG_CODE_SIZE 0x3 + +/** + * The libnet error buffer is 256 bytes long. + */ +#define LIBNET_ERRBUF_SIZE 0x100 + +/** + * IP and TCP options can be up to 40 bytes long. + */ +#define LIBNET_MAXOPTION_SIZE 0x28 + +/* some BSD variants have this endianess problem */ +#if (LIBNET_BSD_BYTE_SWAP) +#define FIX(n) ntohs(n) +#define UNFIX(n) htons(n) +#else +#define FIX(n) (n) +#define UNFIX(n) (n) +#endif + +/* used internally for packet builders */ +#define LIBNET_DO_PAYLOAD(l, p) \ +if (payload_s && !payload) \ +{ \ + snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, \ + "%s(): payload inconsistency\n", __func__); \ + goto bad; \ +} \ +if (payload_s) \ +{ \ + n = libnet_pblock_append(l, p, payload, payload_s); \ + if (n == (uint32_t) - 1) \ + { \ + goto bad; \ + } \ +} \ + +/* used internally for LLDP stuff */ +#define LIBNET_LLDP_TLV_SET_TYPE(tlv, type) (tlv |= (type << 9)) +#define LIBNET_LLDP_TLV_SET_LEN(tlv, len) (tlv |= len) + +/* used internally for checksum stuff */ +#define LIBNET_CKSUM_CARRY(x) \ + (x = (x >> 16) + (x & 0xffff), (~(x + (x >> 16)) & 0xffff)) + +/* used interally for OSPF stuff */ +#define LIBNET_OSPF_AUTHCPY(x, y) \ + memcpy((uint8_t *)x, (uint8_t *)y, sizeof(y)) +#define LIBNET_OSPF_CKSUMBUF(x, y) \ + memcpy((uint8_t *)x, (uint8_t *)y, sizeof(y)) + +/* used internally for NTP leap indicator, version, and mode */ +#define LIBNET_NTP_DO_LI_VN_MODE(li, vn, md) \ + ((uint8_t)((((li) << 6) & 0xc0) | (((vn) << 3) & 0x38) | ((md) & 0x7))) + +/* Not all systems have IFF_LOOPBACK */ +#ifdef IFF_LOOPBACK +#define LIBNET_ISLOOPBACK(p) ((p)->ifr_flags & IFF_LOOPBACK) +#else +#define LIBNET_ISLOOPBACK(p) (strcmp((p)->ifr_name, "lo") == 0) +#endif + +/* advanced mode check */ +#define LIBNET_ISADVMODE(x) (x & 0x08) + +/* context queue macros and constants */ +#define LIBNET_LABEL_SIZE 64 +#define LIBNET_LABEL_DEFAULT "cardshark" +#define CQ_LOCK_UNLOCKED (uint32_t)0x00000000 +#define CQ_LOCK_READ (uint32_t)0x00000001 +#define CQ_LOCK_WRITE (uint32_t)0x00000002 + +/** + * Provides an interface to iterate through the context queue of libnet + * contexts. Before calling this macro, be sure to set the queue using + * libnet_cq_head(). + */ +#define for_each_context_in_cq(l) \ + for (l = libnet_cq_head(); libnet_cq_last(); l = libnet_cq_next()) + +/* return 1 if write lock is set on cq */ +#define cq_is_wlocked() (l_cqd.cq_lock & CQ_LOCK_WRITE) + +/* return 1 if read lock is set on cq */ +#define cq_is_rlocked() (l_cqd.cq_lock & CQ_LOCK_READ) + +/* return 1 if any lock is set on cq */ +#define cq_is_locked() (l_cqd.cq_lock & (CQ_LOCK_READ | CQ_LOCK_WRITE)) + +/* check if a context queue is locked */ +#define check_cq_lock(x) (l_cqd.cq_lock & x) + +#endif /* __LIBNET_MACROS_H */ + +/** + * Local Variables: + * indent-tabs-mode: nil + * c-file-style: "stroustrup" + * End: + */ diff --git a/source/tools/detect/net_diag/tcpping/include/libnet/libnet-structures.h b/source/tools/detect/net_diag/tcpping/include/libnet/libnet-structures.h new file mode 100644 index 0000000000000000000000000000000000000000..4fc135eeef5e0453d6bbb7541415fc75bc6421df --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/include/libnet/libnet-structures.h @@ -0,0 +1,265 @@ +/* + * libnet-structures.h - Network routine library structures header file + * + * Copyright (c) 1998 - 2004 Mike D. Schiffman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef __LIBNET_STRUCTURES_H +#define __LIBNET_STRUCTURES_H + +#if ((_WIN32) && !(__CYGWIN__)) +#include "Packet32.h" +#endif + +/* port list chain structure */ +typedef struct libnet_port_list_chain libnet_plist_t; +struct libnet_port_list_chain +{ + uint16_t node; /* node number */ + uint16_t bport; /* beginning port */ + uint16_t eport; /* terminating port */ + uint8_t id; /* global array offset */ + libnet_plist_t *next; /* next node in the list */ +}; + + +/* libnet statistics structure */ +struct libnet_stats +{ + int64_t packets_sent; /* packets sent */ + int64_t packet_errors; /* packets errors */ + int64_t bytes_written; /* bytes written */ +}; + + +/* + * Libnet ptags are how we identify specific protocol blocks inside the + * list. + */ +typedef int32_t libnet_ptag_t; +#define LIBNET_PTAG_INITIALIZER 0 + + +/* + * Libnet generic protocol block memory object. Sort of a poor man's mbuf. + */ +struct libnet_protocol_block +{ + uint8_t *buf; /* protocol buffer */ + uint32_t b_len; /* length of buf */ + uint16_t h_len; /* header length */ + /* Passed as last argument to libnet_do_checksum(). Not necessarily used + * by that function, it is essentially a pblock specific number, passed + * from _builder to the _do_checksum + * + * Unused for IPV4_H block types. + * + * For protocols that sit on top of IP, it should be the the amount of + * buf that will be included in the checksum, starting from the beginning + * of the header. + */ + uint32_t copied; /* bytes copied - the amount of data copied into buf */ + /* Used and updated by libnet_pblock_append(). */ + uint8_t type; /* type of pblock */ +/* this needs to be updated every time a new packet builder is added */ +/* libnet_diag_dump_pblock_type() also needs updating for every new pblock tag */ +#define LIBNET_PBLOCK_ARP_H 0x01 /* ARP header */ +#define LIBNET_PBLOCK_DHCPV4_H 0x02 /* DHCP v4 header */ +#define LIBNET_PBLOCK_DNSV4_H 0x03 /* DNS v4 header */ +#define LIBNET_PBLOCK_ETH_H 0x04 /* Ethernet header */ +#define LIBNET_PBLOCK_ICMPV4_H 0x05 /* ICMP v4 base header */ +#define LIBNET_PBLOCK_ICMPV4_ECHO_H 0x06 /* ICMP v4 echo header */ +#define LIBNET_PBLOCK_ICMPV4_MASK_H 0x07 /* ICMP v4 mask header */ +#define LIBNET_PBLOCK_ICMPV4_UNREACH_H 0x08 /* ICMP v4 unreach header */ +#define LIBNET_PBLOCK_ICMPV4_TIMXCEED_H 0x09 /* ICMP v4 exceed header */ +#define LIBNET_PBLOCK_ICMPV4_REDIRECT_H 0x0a /* ICMP v4 redirect header */ +#define LIBNET_PBLOCK_ICMPV4_TS_H 0x0b /* ICMP v4 timestamp header */ +#define LIBNET_PBLOCK_IGMP_H 0x0c /* IGMP header */ +#define LIBNET_PBLOCK_IPV4_H 0x0d /* IP v4 header */ +#define LIBNET_PBLOCK_IPO_H 0x0e /* IP v4 options */ +#define LIBNET_PBLOCK_IPDATA 0x0f /* IP data */ +#define LIBNET_PBLOCK_OSPF_H 0x10 /* OSPF base header */ +#define LIBNET_PBLOCK_OSPF_HELLO_H 0x11 /* OSPF hello header */ +#define LIBNET_PBLOCK_OSPF_DBD_H 0x12 /* OSPF dbd header */ +#define LIBNET_PBLOCK_OSPF_LSR_H 0x13 /* OSPF lsr header */ +#define LIBNET_PBLOCK_OSPF_LSU_H 0x14 /* OSPF lsu header */ +#define LIBNET_PBLOCK_OSPF_LSA_H 0x15 /* OSPF lsa header */ +#define LIBNET_PBLOCK_OSPF_AUTH_H 0x16 /* OSPF auth header */ +#define LIBNET_PBLOCK_OSPF_CKSUM 0x17 /* OSPF checksum header */ +#define LIBNET_PBLOCK_LS_RTR_H 0x18 /* linkstate rtr header */ +#define LIBNET_PBLOCK_LS_NET_H 0x19 /* linkstate net header */ +#define LIBNET_PBLOCK_LS_SUM_H 0x1a /* linkstate as sum header */ +#define LIBNET_PBLOCK_LS_AS_EXT_H 0x1b /* linkstate as ext header */ +#define LIBNET_PBLOCK_NTP_H 0x1c /* NTP header */ +#define LIBNET_PBLOCK_RIP_H 0x1d /* RIP header */ +#define LIBNET_PBLOCK_TCP_H 0x1e /* TCP header */ +#define LIBNET_PBLOCK_TCPO_H 0x1f /* TCP options */ +#define LIBNET_PBLOCK_TCPDATA 0x20 /* TCP data */ +#define LIBNET_PBLOCK_UDP_H 0x21 /* UDP header */ +#define LIBNET_PBLOCK_VRRP_H 0x22 /* VRRP header */ +#define LIBNET_PBLOCK_DATA_H 0x23 /* generic data */ +#define LIBNET_PBLOCK_CDP_H 0x24 /* CDP header */ +#define LIBNET_PBLOCK_IPSEC_ESP_HDR_H 0x25 /* IPSEC ESP header */ +#define LIBNET_PBLOCK_IPSEC_ESP_FTR_H 0x26 /* IPSEC ESP footer */ +#define LIBNET_PBLOCK_IPSEC_AH_H 0x27 /* IPSEC AH header */ +#define LIBNET_PBLOCK_802_1Q_H 0x28 /* 802.1q header */ +#define LIBNET_PBLOCK_802_2_H 0x29 /* 802.2 header */ +#define LIBNET_PBLOCK_802_2SNAP_H 0x2a /* 802.2 SNAP header */ +#define LIBNET_PBLOCK_802_3_H 0x2b /* 802.3 header */ +#define LIBNET_PBLOCK_STP_CONF_H 0x2c /* STP configuration header */ +#define LIBNET_PBLOCK_STP_TCN_H 0x2d /* STP TCN header */ +#define LIBNET_PBLOCK_ISL_H 0x2e /* ISL header */ +#define LIBNET_PBLOCK_IPV6_H 0x2f /* IP v6 header */ +#define LIBNET_PBLOCK_802_1X_H 0x30 /* 802.1x header */ +#define LIBNET_PBLOCK_RPC_CALL_H 0x31 /* RPC Call header */ +#define LIBNET_PBLOCK_MPLS_H 0x32 /* MPLS header */ +#define LIBNET_PBLOCK_FDDI_H 0x33 /* FDDI header */ +#define LIBNET_PBLOCK_TOKEN_RING_H 0x34 /* TOKEN RING header */ +#define LIBNET_PBLOCK_BGP4_HEADER_H 0x35 /* BGP4 header */ +#define LIBNET_PBLOCK_BGP4_OPEN_H 0x36 /* BGP4 open header */ +#define LIBNET_PBLOCK_BGP4_UPDATE_H 0x37 /* BGP4 update header */ +#define LIBNET_PBLOCK_BGP4_NOTIFICATION_H 0x38 /* BGP4 notification header */ +#define LIBNET_PBLOCK_GRE_H 0x39 /* GRE header */ +#define LIBNET_PBLOCK_GRE_SRE_H 0x3a /* GRE SRE header */ +#define LIBNET_PBLOCK_IPV6_FRAG_H 0x3b /* IPv6 frag header */ +#define LIBNET_PBLOCK_IPV6_ROUTING_H 0x3c /* IPv6 routing header */ +#define LIBNET_PBLOCK_IPV6_DESTOPTS_H 0x3d /* IPv6 dest opts header */ +#define LIBNET_PBLOCK_IPV6_HBHOPTS_H 0x3e /* IPv6 hop/hop opts header */ +#define LIBNET_PBLOCK_SEBEK_H 0x3f /* Sebek header */ +#define LIBNET_PBLOCK_HSRP_H 0x40 /* HSRP header */ +#define LIBNET_PBLOCK_ICMPV6_H 0x41 /* ICMPv6 header (unused) */ +#define LIBNET_PBLOCK_ICMPV6_ECHO_H 0x46 /* ICMPv6 echo header */ +#define LIBNET_PBLOCK_ICMPV6_UNREACH_H 0x42 /* ICMPv6 unreach header */ +#define LIBNET_PBLOCK_ICMPV6_NDP_NSOL_H 0x43 /* ICMPv6 NDP neighbor solicitation header */ +#define LIBNET_PBLOCK_ICMPV6_NDP_NADV_H 0x44 /* ICMPv6 NDP neighbor advertisement header */ +#define LIBNET_PBLOCK_ICMPV6_NDP_OPT_H 0x45 /* ICMPv6 NDP option */ +#define LIBNET_PBLOCK_LLDP_H 0x50 /* LLDP header */ +#define LIBNET_PBLOCK_LLDP_CHASSIS_H 0x51 /* LLDP Chassis header */ +#define LIBNET_PBLOCK_LLDP_PORT_H 0x52 /* LLDP Port header */ +#define LIBNET_PBLOCK_LLDP_TTL_H 0x53 /* LLDP TTL header */ +#define LIBNET_PBLOCK_LLDP_END_H 0x54 /* LLDP End of LLDPDU header */ +#define LIBNET_PBLOCK_LLDP_ORG_SPEC_H 0x55 /* LLDP Organization Specific header */ + + uint8_t flags; /* control flags */ +#define LIBNET_PBLOCK_DO_CHECKSUM 0x01 /* needs a checksum */ + libnet_ptag_t ptag; /* protocol block tag */ + /* Chains are built from highest level protocol, towards the link level, so + * prev traverses away from link level, and next traverses towards the + * link level. + */ + struct libnet_protocol_block *next; /* next pblock */ + struct libnet_protocol_block *prev; /* prev pblock */ +}; +typedef struct libnet_protocol_block libnet_pblock_t; + + +/* + * Libnet context + * Opaque structure. Nothing in here should ever been touched first hand by + * the applications programmer. + */ +struct libnet_context +{ +#if ((_WIN32) && !(__CYGWIN__)) + SOCKET fd; + LPADAPTER lpAdapter; +#else + int fd; /* file descriptor of packet device */ +#endif + int injection_type; /* one of: */ +#define LIBNET_NONE 0xf8 /* no injection type, only construct packets */ +#define LIBNET_LINK 0x00 /* link-layer interface */ +#define LIBNET_RAW4 0x01 /* raw socket interface (ipv4) */ +#define LIBNET_RAW6 0x02 /* raw socket interface (ipv6) */ +/* the following should actually set a flag in the flags variable above */ +#define LIBNET_LINK_ADV 0x08 /* advanced mode link-layer */ +#define LIBNET_RAW4_ADV 0x09 /* advanced mode raw socket (ipv4) */ +#define LIBNET_RAW6_ADV 0x0a /* advanced mode raw socket (ipv6) */ +#define LIBNET_ADV_MASK 0x08 /* mask to determine adv mode */ + + /* _blocks is the highest level, and _end is closest to link-level */ + libnet_pblock_t *protocol_blocks; /* protocol headers / data */ + libnet_pblock_t *pblock_end; /* last node in list */ + uint32_t n_pblocks; /* number of pblocks */ + + int link_type; /* link-layer type, a DLT_ value. */ + /* These are the only values used by libnet (see libnet_build_arp and + * libnet_build_link). Other values are assigned by the various + * libnet_link_*.c OS support functions, but are not yet used or supported, + * they are effectively dead code. claims these two are invariant + * across operating systems... hopefully it is correct! + */ +#ifndef DLT_EN10MB +# define DLT_EN10MB 1 /* Ethernet (10Mb) */ +#endif +#ifndef DLT_IEEE802 +# define DLT_IEEE802 6 /* IEEE 802 Networks */ +#endif + + int link_offset; /* link-layer header size */ + int aligner; /* used to align packets */ + char *device; /* device name */ + + struct libnet_stats stats; /* statistics */ + libnet_ptag_t ptag_state; /* state holder for pblock tag */ + char label[LIBNET_LABEL_SIZE]; /* textual label for cq interface */ + + char err_buf[LIBNET_ERRBUF_SIZE]; /* error buffer */ + uint32_t total_size; /* total size */ + + struct libnet_ether_addr link_addr; /* Link HW addr */ +}; +typedef struct libnet_context libnet_t; + +/* + * Libnet context queue structure + * Opaque structure. Nothing in here should ever been touched first hand by + * the applications programmer. + */ +typedef struct _libnet_context_queue libnet_cq_t; +struct _libnet_context_queue +{ + libnet_t *context; /* pointer to libnet context */ + libnet_cq_t *next; /* next node in the list */ + libnet_cq_t *prev; /* previous node in the list */ +}; + +struct _libnet_context_queue_descriptor +{ + uint32_t node; /* number of nodes in the list */ + uint32_t cq_lock; /* lock status */ + libnet_cq_t *current; /* current context */ +}; +typedef struct _libnet_context_queue_descriptor libnet_cqd_t; + +#endif /* __LIBNET_STRUCTURES_H */ + +/** + * Local Variables: + * indent-tabs-mode: nil + * c-file-style: "stroustrup" + * End: + */ diff --git a/source/tools/detect/net_diag/tcpping/include/libnet/libnet-types.h b/source/tools/detect/net_diag/tcpping/include/libnet/libnet-types.h new file mode 100644 index 0000000000000000000000000000000000000000..71f59cf2e2a70872c594f497415cf207f126c0fc --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/include/libnet/libnet-types.h @@ -0,0 +1,45 @@ +/* + * $Id: libnet-types.h,v 1.3 2004/01/03 20:31:00 mike Exp $ + * + * libnet-types.h - Network routine library macro header file + * + * Copyright (c) 1998 - 2004 Mike D. Schiffman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef __LIBNET_TYPES_H +#define __LIBNET_TYPES_H + +/* libnet should be using the standard type names, so mapping standard + * to non-standard should not be necessary. */ + +#endif /* __LIBNET_TYPES_H */ + +/** + * Local Variables: + * indent-tabs-mode: nil + * c-file-style: "stroustrup" + * End: + */ diff --git a/source/tools/detect/net_diag/tcpping/lib/libnet.a b/source/tools/detect/net_diag/tcpping/lib/libnet.a new file mode 100755 index 0000000000000000000000000000000000000000..104172bf5bad8fa414b69ece7c31cb19442d81d6 Binary files /dev/null and b/source/tools/detect/net_diag/tcpping/lib/libnet.a differ diff --git a/source/tools/detect/net_diag/tcpping/lib/libnet.la b/source/tools/detect/net_diag/tcpping/lib/libnet.la new file mode 100755 index 0000000000000000000000000000000000000000..991748e01b0b280f9ca6470ec208ec904ed76625 --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/lib/libnet.la @@ -0,0 +1,41 @@ +# libnet.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.2 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='libnet.so.9' + +# Names of this library. +library_names='libnet.so.9.0.0 libnet.so.9 libnet.so' + +# The name of the static archive. +old_library='libnet.a' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='' + +# Libraries that this one depends upon. +dependency_libs='' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libnet. +current=9 +age=0 +revision=0 + +# Is this an already installed library? +installed=yes + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/usr/local/lib' diff --git a/source/tools/detect/net_diag/tcpping/lib/libnet.so b/source/tools/detect/net_diag/tcpping/lib/libnet.so new file mode 100755 index 0000000000000000000000000000000000000000..1ae41526dd4c1b38121f78576b34615c65451acb Binary files /dev/null and b/source/tools/detect/net_diag/tcpping/lib/libnet.so differ diff --git a/source/tools/detect/net_diag/tcpping/lib/libnet.so.9 b/source/tools/detect/net_diag/tcpping/lib/libnet.so.9 new file mode 100755 index 0000000000000000000000000000000000000000..1ae41526dd4c1b38121f78576b34615c65451acb Binary files /dev/null and b/source/tools/detect/net_diag/tcpping/lib/libnet.so.9 differ diff --git a/source/tools/detect/net_diag/tcpping/lib/libnet.so.9.0.0 b/source/tools/detect/net_diag/tcpping/lib/libnet.so.9.0.0 new file mode 100755 index 0000000000000000000000000000000000000000..1ae41526dd4c1b38121f78576b34615c65451acb Binary files /dev/null and b/source/tools/detect/net_diag/tcpping/lib/libnet.so.9.0.0 differ diff --git a/source/tools/detect/net_diag/tcpping/src/cJSON.c b/source/tools/detect/net_diag/tcpping/src/cJSON.c new file mode 100644 index 0000000000000000000000000000000000000000..030311ce54db8626e16cb0f49b6baea9e386e46f --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/src/cJSON.c @@ -0,0 +1,3110 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +/* disable warnings about old C89 functions in MSVC */ +#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) +#define _CRT_SECURE_NO_DEPRECATE +#endif + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif +#if defined(_MSC_VER) +#pragma warning (push) +/* disable warning about single line comments in system headers */ +#pragma warning (disable : 4001) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_LOCALES +#include +#endif + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif + +#include "cJSON.h" + +/* define our own boolean type */ +#ifdef true +#undef true +#endif +#define true ((cJSON_bool)1) + +#ifdef false +#undef false +#endif +#define false ((cJSON_bool)0) + +/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ +#ifndef isinf +#define isinf(d) (isnan((d - d)) && !isnan(d)) +#endif +#ifndef isnan +#define isnan(d) (d != d) +#endif + +#ifndef NAN +#ifdef _WIN32 +#define NAN sqrt(-1.0) +#else +#define NAN 0.0/0.0 +#endif +#endif + +typedef struct { + const unsigned char *json; + size_t position; +} error; +static error global_error = { NULL, 0 }; + +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char*) (global_error.json + global_error.position); +} + +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) +{ + if (!cJSON_IsString(item)) + { + return NULL; + } + + return item->valuestring; +} + +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) +{ + if (!cJSON_IsNumber(item)) + { + return (double) NAN; + } + + return item->valuedouble; +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 14) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +CJSON_PUBLIC(const char*) cJSON_Version(void) +{ + static char version[15]; + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) +{ + if ((string1 == NULL) || (string2 == NULL)) + { + return 1; + } + + if (string1 == string2) + { + return 0; + } + + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) + { + if (*string1 == '\0') + { + return 0; + } + } + + return tolower(*string1) - tolower(*string2); +} + +typedef struct internal_hooks +{ + void *(CJSON_CDECL *allocate)(size_t size); + void (CJSON_CDECL *deallocate)(void *pointer); + void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); +} internal_hooks; + +#if defined(_MSC_VER) +/* work around MSVC error C2322: '...' address of dllimport '...' is not static */ +static void * CJSON_CDECL internal_malloc(size_t size) +{ + return malloc(size); +} +static void CJSON_CDECL internal_free(void *pointer) +{ + free(pointer); +} +static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) +{ + return realloc(pointer, size); +} +#else +#define internal_malloc malloc +#define internal_free free +#define internal_realloc realloc +#endif + +/* strlen of character literals resolved at compile time */ +#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) + +static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; + +static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) + { + return NULL; + } + + length = strlen((const char*)string) + sizeof(""); + copy = (unsigned char*)hooks->allocate(length); + if (copy == NULL) + { + return NULL; + } + memcpy(copy, string, length); + + return copy; +} + +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (hooks == NULL) + { + /* Reset hooks */ + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; + return; + } + + global_hooks.allocate = malloc; + if (hooks->malloc_fn != NULL) + { + global_hooks.allocate = hooks->malloc_fn; + } + + global_hooks.deallocate = free; + if (hooks->free_fn != NULL) + { + global_hooks.deallocate = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + global_hooks.reallocate = NULL; + if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) + { + global_hooks.reallocate = realloc; + } +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) +{ + cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); + if (node) + { + memset(node, '\0', sizeof(cJSON)); + } + + return node; +} + +/* Delete a cJSON structure. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +{ + cJSON *next = NULL; + while (item != NULL) + { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) + { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ +#ifdef ENABLE_LOCALES + struct lconv *lconv = localeconv(); + return (unsigned char) lconv->decimal_point[0]; +#else + return '.'; +#endif +} + +typedef struct +{ + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + + number = strtod((const char*)number_c_string, (char**)&after_end); + if (number_c_string == after_end) + { + return false; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)number; + } + + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) + { + object->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = (int)number; + } + + return object->valuedouble = number; +} + +CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) +{ + char *copy = NULL; + /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ + if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) + { + return NULL; + } + if (strlen(valuestring) <= strlen(object->valuestring)) + { + strcpy(object->valuestring, valuestring); + return object->valuestring; + } + copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); + if (copy == NULL) + { + return NULL; + } + if (object->valuestring != NULL) + { + cJSON_free(object->valuestring); + } + object->valuestring = copy; + + return copy; +} + +typedef struct +{ + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char* ensure(printbuffer * const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) + { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) + { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) + { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) + { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) + { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) + { + newsize = INT_MAX; + } + else + { + return NULL; + } + } + else + { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) + { + /* reallocate with realloc if available */ + newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } + else + { + /* otherwise reallocate manually */ + newbuffer = (unsigned char*)p->hooks.allocate(newsize); + if (!newbuffer) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + + memcpy(newbuffer, p->buffer, p->offset + 1); + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) + { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char*)buffer_pointer); +} + +/* securely comparison of floating-point variables */ +static cJSON_bool compare_double(double a, double b) +{ + double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); + return (fabs(a - b) <= maxVal * DBL_EPSILON); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test = 0.0; + + if (output_buffer == NULL) + { + return false; + } + + /* This checks for NaN and Infinity */ + if (isnan(d) || isinf(d)) + { + length = sprintf((char*)number_buffer, "null"); + } + else + { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char*)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) + { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char*)number_buffer, "%1.17g", d); + } + } + + /* sprintf failed or buffer overrun occurred */ + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) + { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); + if (output_pointer == NULL) + { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t)length); i++) + { + if (number_buffer[i] == decimal_point) + { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t)length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char * const input) +{ + unsigned int h = 0; + size_t i = 0; + + for (i = 0; i < 4; i++) + { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) + { + h += (unsigned int) input[i] - '0'; + } + else if ((input[i] >= 'A') && (input[i] <= 'F')) + { + h += (unsigned int) 10 + input[i] - 'A'; + } + else if ((input[i] >= 'a') && (input[i] <= 'f')) + { + h += (unsigned int) 10 + input[i] - 'a'; + } + else /* invalid */ + { + return 0; + } + + if (i < 3) + { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 + * A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) + { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) + { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) + { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) + { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } + else + { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) + { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } + else if (codepoint < 0x800) + { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } + else if (codepoint < 0x10000) + { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } + else if (codepoint <= 0x10FFFF) + { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } + else + { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) + { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } + else + { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') + { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) + { + /* is escape sequence */ + if (input_end[0] == '\\') + { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) + { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) + { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); + if (output == NULL) + { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) + { + if (*input_pointer != '\\') + { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else + { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) + { + goto fail; + } + + switch (input_pointer[1]) + { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = (char*)output; + + input_buffer->offset = (size_t) (input_end - input_buffer->content); + input_buffer->offset++; + + return true; + +fail: + if (output != NULL) + { + input_buffer->hooks.deallocate(output); + } + + if (input_pointer != NULL) + { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + + return false; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) + { + return false; + } + + /* empty string */ + if (input == NULL) + { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) + { + switch (*input_pointer) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) + { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) + { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) + { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) + { + /* normal character, copy */ + *output_pointer = *input_pointer; + } + else + { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) + { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) +{ + return print_string_ptr((unsigned char*)item->valuestring, p); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) + { + return NULL; + } + + if (cannot_access_at_index(buffer, 0)) + { + return buffer; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) + { + buffer->offset++; + } + + if (buffer->offset == buffer->length) + { + buffer->offset--; + } + + return buffer; +} + +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) + { + return NULL; + } + + if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) + { + buffer->offset += 3; + } + + return buffer; +} + +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + size_t buffer_length; + + if (NULL == value) + { + return NULL; + } + + /* Adding null character size due to require_null_terminated. */ + buffer_length = strlen(value) + sizeof(""); + + return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL || 0 == buffer_length) + { + goto fail; + } + + buffer.content = (const unsigned char*)value; + buffer.length = buffer_length; + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item(&global_hooks); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) + { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { + goto fail; + } + } + if (return_parse_end) + { + *return_parse_end = (const char*)buffer_at_offset(&buffer); + } + + return item; + +fail: + if (item != NULL) + { + cJSON_Delete(item); + } + + if (value != NULL) + { + error local_error; + local_error.json = (const unsigned char*)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) + { + local_error.position = buffer.offset; + } + else if (buffer.length > 0) + { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) + { + *return_parse_end = (const char*)local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) +{ + return cJSON_ParseWithOpts(value, 0, 0); +} + +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) +{ + return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); +} + +#define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) + +static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) +{ + static const size_t default_buffer_size = 256; + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); + buffer->length = default_buffer_size; + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) + { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) + { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) + { + printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + buffer->buffer = NULL; + } + else /* otherwise copy the JSON over to a new buffer */ + { + printed = (unsigned char*) hooks->allocate(buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + +fail: + if (buffer->buffer != NULL) + { + hooks->deallocate(buffer->buffer); + } + + if (printed != NULL) + { + hooks->deallocate(printed); + } + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) +{ + return (char*)print(item, true, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) +{ + return (char*)print(item, false, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if (prebuffer < 0) + { + return NULL; + } + + p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); + if (!p.buffer) + { + return NULL; + } + + p.length = (size_t)prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if (!print_value(item, &p)) + { + global_hooks.deallocate(p.buffer); + return NULL; + } + + return (char*)p.buffer; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ((length < 0) || (buffer == NULL)) + { + return false; + } + + p.buffer = (unsigned char*)buffer; + p.length = (size_t)length; + p.offset = 0; + p.noalloc = true; + p.format = format; + p.hooks = global_hooks; + + return print_value(item, &p); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) + { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + /* false */ + if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + /* true */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) + { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) + { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) + { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) + { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) + { + return parse_object(item, input_buffer); + } + + return false; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) + { + return false; + } + + switch ((item->type) & 0xFF) + { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: + { + size_t raw_length = 0; + if (item->valuestring == NULL) + { + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) + { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') + { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) + { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') + { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + if (head != NULL) { + head->prev = current_item; + } + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an array to text */ +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_element = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) + { + if (!print_value(current_element, output_buffer)) + { + return false; + } + update_offset(output_buffer); + if (current_element->next) + { + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ','; + if(output_buffer->format) + { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) + { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) + { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) + { + goto fail; /* failed to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) + { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) + { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + if (head != NULL) { + head->prev = current_item; + } + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output: */ + length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) + { + if (output_buffer->format) + { + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) + { + return false; + } + for (i = 0; i < output_buffer->depth; i++) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + if (current_item->next) + { + *output_pointer++ = ','; + } + + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) + { + return false; + } + if (output_buffer->format) + { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) + { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Get Array size/item / object item. */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +{ + cJSON *child = NULL; + size_t size = 0; + + if (array == NULL) + { + return 0; + } + + child = array->child; + + while(child != NULL) + { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int)size; +} + +static cJSON* get_array_item(const cJSON *array, size_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) + { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) + { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) + { + return NULL; + } + + return get_array_item(array, (size_t)index); +} + +static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) + { + return NULL; + } + + current_element = object->child; + if (case_sensitive) + { + while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) + { + current_element = current_element->next; + } + } + else + { + while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) + { + current_element = current_element->next; + } + } + + if ((current_element == NULL) || (current_element->string == NULL)) { + return NULL; + } + + return current_element; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, false); +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) +{ + cJSON *reference = NULL; + if (item == NULL) + { + return NULL; + } + + reference = cJSON_New_Item(hooks); + if (reference == NULL) + { + return NULL; + } + + memcpy(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} + +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; + + if ((item == NULL) || (array == NULL) || (array == item)) + { + return false; + } + + child = array->child; + /* + * To find the last item in array quickly, we use prev in array + */ + if (child == NULL) + { + /* list is empty, start new one */ + array->child = item; + item->prev = item; + item->next = NULL; + } + else + { + /* append to the end */ + if (child->prev) + { + suffix_object(child->prev, item); + array->child->prev = item; + } + } + + return true; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + return add_item_to_array(array, item); +} + +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif +/* helper function to cast away const */ +static void* cast_away_const(const void* string) +{ + return (void*)string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif + + +static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) +{ + char *new_key = NULL; + int new_type = cJSON_Invalid; + + if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) + { + return false; + } + + if (constant_key) + { + new_key = (char*)cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; + } + else + { + new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (new_key == NULL) + { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + hooks->deallocate(item->string); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array(object, item); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + return add_item_to_object(object, string, item, &global_hooks, false); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + return add_item_to_object(object, string, item, &global_hooks, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + if (array == NULL) + { + return false; + } + + return add_item_to_array(array, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +{ + if ((object == NULL) || (string == NULL)) + { + return false; + } + + return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, &global_hooks, false)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, &global_hooks, false)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, &global_hooks, false)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, &global_hooks, false)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, &global_hooks, false)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, &global_hooks, false)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, &global_hooks, false)) + { + return array; + } + + cJSON_Delete(array); + return NULL; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) +{ + if ((parent == NULL) || (item == NULL)) + { + return NULL; + } + + if (item != parent->child) + { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) + { + /* first element */ + parent->child = item->next; + } + else if (item->next == NULL) + { + /* last element */ + parent->child->prev = item->prev; + } + + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) + { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} + +/* Replace array/object items with new ones. */ +CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) + { + return false; + } + + after_inserted = get_array_item(array, (size_t)which); + if (after_inserted == NULL) + { + return add_item_to_array(array, newitem); + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) + { + array->child = newitem; + } + else + { + newitem->prev->next = newitem; + } + return true; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) +{ + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + { + return false; + } + + if (replacement == item) + { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) + { + replacement->next->prev = replacement; + } + if (parent->child == item) + { + if (parent->child->prev == parent->child) + { + replacement->prev = replacement; + } + parent->child = replacement; + } + else + { /* + * To find the last item in array quickly, we use prev in array. + * We can't modify the last item's next pointer where this item was the parent's child + */ + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + if (replacement->next == NULL) + { + parent->child->prev = replacement; + } + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +{ + if (which < 0) + { + return false; + } + + return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) +{ + if ((replacement == NULL) || (string == NULL)) + { + return false; + } + + /* replace the name in the replacement */ + if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) + { + cJSON_free(replacement->string); + } + replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + replacement->type &= ~cJSON_StringIsConst; + + return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +{ + return replace_item_in_object(object, string, newitem, false); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +{ + return replace_item_in_object(object, string, newitem, true); +} + +/* Create basic types: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = boolean ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_String; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = (char*)cast_away_const(string); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Object | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Array | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Raw; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type=cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber((double)numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (strings == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateString(strings[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p,n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +/* Duplication */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if (!item) + { + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(&global_hooks); + if (!newitem) + { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) + { + newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + if (!newitem->valuestring) + { + goto fail; + } + } + if (item->string) + { + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + if (!newitem->string) + { + goto fail; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) + { + return newitem; + } + /* Walk the ->next chain for the child. */ + child = item->child; + while (child != NULL) + { + newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) + { + goto fail; + } + if (next != NULL) + { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + if (newitem && newitem->child) + { + newitem->child->prev = newchild; + } + + return newitem; + +fail: + if (newitem != NULL) + { + cJSON_Delete(newitem); + } + + return NULL; +} + +static void skip_oneline_comment(char **input) +{ + *input += static_strlen("//"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if ((*input)[0] == '\n') { + *input += static_strlen("\n"); + return; + } + } +} + +static void skip_multiline_comment(char **input) +{ + *input += static_strlen("/*"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if (((*input)[0] == '*') && ((*input)[1] == '/')) + { + *input += static_strlen("*/"); + return; + } + } +} + +static void minify_string(char **input, char **output) { + (*output)[0] = (*input)[0]; + *input += static_strlen("\""); + *output += static_strlen("\""); + + + for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { + (*output)[0] = (*input)[0]; + + if ((*input)[0] == '\"') { + (*output)[0] = '\"'; + *input += static_strlen("\""); + *output += static_strlen("\""); + return; + } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { + (*output)[1] = (*input)[1]; + *input += static_strlen("\""); + *output += static_strlen("\""); + } + } +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + char *into = json; + + if (json == NULL) + { + return; + } + + while (json[0] != '\0') + { + switch (json[0]) + { + case ' ': + case '\t': + case '\r': + case '\n': + json++; + break; + + case '/': + if (json[1] == '/') + { + skip_oneline_comment(&json); + } + else if (json[1] == '*') + { + skip_multiline_comment(&json); + } else { + json++; + } + break; + + case '\"': + minify_string(&json, (char**)&into); + break; + + default: + into[0] = json[0]; + json++; + into++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + { + return false; + } + + /* check if type is valid */ + switch (a->type & 0xFF) + { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if (a == b) + { + return true; + } + + switch (a->type & 0xFF) + { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if (compare_double(a->valuedouble, b->valuedouble)) + { + return true; + } + return false; + + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) + { + return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) + { + return true; + } + + return false; + + case cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) + { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } + + return true; + } + + case cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) + { + return false; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + } + + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return false; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) +{ + return global_hooks.allocate(size); +} + +CJSON_PUBLIC(void) cJSON_free(void *object) +{ + global_hooks.deallocate(object); +} diff --git a/source/tools/detect/net_diag/tcpping/src/tcpping.c b/source/tools/detect/net_diag/tcpping/src/tcpping.c new file mode 100644 index 0000000000000000000000000000000000000000..d01975a9a2760f2ac63e465b51b7c4a5d43349a0 --- /dev/null +++ b/source/tools/detect/net_diag/tcpping/src/tcpping.c @@ -0,0 +1,668 @@ +/* + * Author: Chen Tao + * Create: Mon Jan 17 14:12:28 2022 + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tcpping.skel.h" +#include "data_define.h" +#include +#include +#include "cJSON.h" + +//#define DEBUG +#define BTF_PATH_MAX 128 +char btf_path_buf[BTF_PATH_MAX] = "/tmp/vmlinux-"; +bool exiting = false; +libnet_t *handle; /* Libnet句柄 */ +char error[LIBNET_ERRBUF_SIZE]; /* 出错信息 */ + +struct trace_path { + char *path; + int to; + int from; +}; + +static const struct trace_path trace_path[] = { + {"t_trans", PT_KERN_RAW_SENDMSG, PT_USER}, + {"t_ip", PT_KERN_DEV_QUE_XMIT, PT_KERN_RAW_SENDMSG}, + {"r_remote", PT_KERN_NET_RECV_SKB, PT_KERN_DEV_QUE_XMIT}, + {"r_dev", PT_KERN_IP_RCV, PT_KERN_NET_RECV_SKB}, + {"r_ip", PT_KERN_TCP_V4_RCV, PT_KERN_IP_RCV}, + {"delta", PT_KERN_TCP_V4_RCV, PT_USER}, +}; + +struct trace_para { + struct tuple_info tuple; + int pack_nr; /* package count */ + int delay; /* delay send ms*/ + int output_mode; /*0:print, 1:json */ + FILE *file; + cJSON *root; + int cpu; +}; + +struct trace_para trace_para = { + .tuple = { + .src_ip = 0, + .dst_ip = 0, + .src_port = 30330, + .dst_port = 80, + }, + .pack_nr = 100, + .delay = 1, /* 1ms */ + .output_mode = 0, + .file = NULL, + .root = NULL, + .cpu = 0, +}; + +struct raw_times { + __u64 times[10]; +}; + +struct trace_time { + struct raw_times *time; + int time_id; + int out_id; + int in_id; + int size; +}; + +struct trace_time trace_time = { + .time = NULL, + .time_id = 0, + .out_id = 0, + .in_id = 0, + .size = 0, +}; + +struct tuple_info tuple = { + .src_ip = 0, + .dst_ip = 0, + .src_port = 0, + .dst_port = 0, +}; + +struct data { + __u32 t_trans; + __u32 t_ip; + __u32 t_dev; + __u32 r_remote; + __u32 r_dev; + __u32 r_ip; + __u32 delta; +}; + +struct data data_min = {0}; +struct data data_avg = {0}; +struct data data_max = {0}; +struct data image = {0}; + +#define DATA_MIN(path) data_min.path = data_min.path < image.path ? data_min.path : image.path; +#define DATA_MAX(path) data_max.path = data_max.path > image.path ? data_max.path : image.path; +#define DATA_AVG(path) data_avg.path = data_avg.path + image.path; +#define DELTA(path, to, from) image.path = (time[nr].times[to] - time[nr].times[from]) / 1000; + +//static char path[5] = {'v', '>', '^', 'v', '<'}; + +static void json_dump(int nr) +{ + int i; + cJSON *root; + char *out; + cJSON *next; + + root = trace_para.root; + next = cJSON_CreateObject(); + cJSON_AddItemToObject(root, "data", next); + cJSON_AddNumberToObject(next, "seq", nr); + for (i = 0; i < sizeof(trace_path) / sizeof(struct trace_path); i++) { + cJSON_AddNumberToObject(next, trace_path[i].path, + (trace_time.time[nr].times[trace_path[i].to] - + trace_time.time[nr].times[trace_path[i].from]) / 1000); + } + if (nr == trace_para.pack_nr - 1) { + out = cJSON_Print(root); + if (trace_para.file) { + fprintf(trace_para.file, "%s\n", out); + } + free(out); + } +} + +static int trace_output_init(char *path) +{ + + trace_para.file = fopen(path, "w+"); + if (!trace_para.file) { + printf("output path is wrong:%s\n", path); + return -1; + } + trace_para.root = cJSON_CreateObject(); + if (!trace_para.root) { + printf("create json root failed\n"); + return -1; + } + + return 0; +} + +static void trace_output_close(void) +{ + if (trace_para.file) + fclose(trace_para.file); + if (trace_para.root) + cJSON_Delete(trace_para.root); +} + +/* +static char move_path(int local, int nr) +{ + if (nr % 5 == local) { + return path[local]; + } else if (local == 0 || local == 2 || local == 0) { + return '|'; + } else { + return '-'; + } +} +*/ + +static void image_show(int nr) +{ + struct raw_times *time = NULL; + struct in_addr dip = { + .s_addr = trace_para.tuple.dst_ip, + }; + + time = trace_time.time; + DELTA(t_trans, PT_KERN_RAW_SENDMSG, PT_USER) + DELTA(t_ip, PT_KERN_DEV_QUE_XMIT, PT_KERN_RAW_SENDMSG) + DELTA(r_remote, PT_KERN_NET_RECV_SKB, PT_KERN_DEV_QUE_XMIT) + DELTA(r_dev, PT_KERN_IP_RCV, PT_KERN_NET_RECV_SKB) + DELTA(r_ip, PT_KERN_TCP_V4_RCV, PT_KERN_IP_RCV) + DELTA(delta, PT_KERN_TCP_V4_RCV, PT_USER) + + DATA_MIN(t_trans) + DATA_MIN(t_ip) + DATA_MIN(r_remote) + DATA_MIN(r_dev) + DATA_MIN(r_ip) + DATA_MIN(delta) + + DATA_MAX(t_trans) + DATA_MAX(t_ip) + DATA_MAX(r_remote) + DATA_MAX(r_dev) + DATA_MAX(r_ip) + DATA_MAX(delta) + + DATA_AVG(t_trans) + DATA_AVG(t_ip) + DATA_AVG(r_remote) + DATA_AVG(r_dev) + DATA_AVG(r_ip) + DATA_AVG(delta) + + printf("+-------------------tcp-trace---------------------+\n"); + printf("| seq:%5d unit:usec |\n", nr); + printf("| +-------+ %5u +---------------+ |\n", image.delta); + printf("| | local | ---------> | %12s| |\n", inet_ntoa(dip)); + printf("| +-------+ +---------------+ |\n"); + printf("| | user | |\n"); + printf("| ------------------------ +--------+ |\n"); + printf("| | | | | |\n"); + printf("| %5u | trans layer| | | |\n", image.t_trans); + printf("| ------------------------ | | |\n"); + printf("| | | | | |\n"); + printf("| %5u | ip layer | %5u | | |\n", image.t_ip, image.r_ip); + printf("| |----------------- | ^ |\n"); + printf("| | | v | |\n"); + printf("| | dev layer | %5u | | |\n", image.r_dev); + printf("| ------|------------|---- | | |\n"); + printf("| v | %5u | | |\n", image.r_remote); + printf("| | +-------<-----+ | |\n"); + printf("| +---------------->------------------+ |\n"); + printf("| |\n"); + printf("+-------------------------------------------------+\n"); +} + +static void record_start_time(int nr) +{ + struct timespec ts = {0}; + __u64 curr; + + clock_gettime(CLOCK_MONOTONIC, &ts); + curr = ts.tv_sec * 1000000000 + ts.tv_nsec; + if (!trace_time.time) { + trace_time.time = (struct raw_times *)calloc(nr, sizeof(struct raw_times)); + trace_time.size = nr; + } + trace_time.time[trace_time.time_id++].times[PT_USER] = curr; +} + +static int probe(int nr, __u32 src_ip, __u32 dst_ip, __u16 src_port, + __u16 dst_port) +{ + int packet_size; /* 构造的数据包大小 */ + libnet_ptag_t ip_tag, tcp_tag, data_tag; /* 各层build函数返回值 */ + u_short proto = IPPROTO_TCP; /* 传输层协议 */ + u_char payload[64] = {0}; /* 承载数据的数组,初值为空 */ + u_long payload_s = 0; /* 承载数据的长度,初值为0 */ + int i; + int seq = 0; + int ret; + + /* + // 初始化Libnet + if ((handle = libnet_init(LIBNET_RAW4, NULL, error)) == NULL) { + printf("libnet_init failure:%s\n", error); + return -1; + } + */ + strncpy((char *)payload, "test", sizeof(payload)-1); /* 构造负载的内容 */ + payload_s = strlen((char *)payload); /* 计算负载内容的长度 */ + packet_size = LIBNET_IPV4_H + LIBNET_TCP_H + payload_s; + for (i = 0; i < nr; i++) { + //payload_s = 0; + //data_tag = libnet_build_data(payload, payload_s, handle, 0); + data_tag = 0; + //printf("data_tag:%d, libnet_tcp:%d\n", (int)data_tag, LIBNET_TCP_H); + if (data_tag < 0) { + printf("failed to add payload:%s\n", libnet_geterror(handle)); + //libnet_destroy(handle); /* 释放句柄 */ + return -1; + } + tcp_tag = libnet_build_tcp( + src_port, /* 源端口 */ + dst_port, /* 目的端口 */ + seq, /* 序列号 */ + 0, /* 确认号 */ + TH_SYN, /* Control flags */ + 0, /* 窗口尺寸 */ + 0, /* 校验和,0为自动计算 */ + 0, /* 紧急指针 */ + LIBNET_TCP_H + payload_s, /* 长度 */ + payload, /* 负载内容 */ + payload_s, /* 负载内容长度 */ + handle, /* libnet句柄 */ + 0 /* 新建包 */ + ); + if (tcp_tag == -1) { + printf("libnet_build_tcp failure\n"); + //libnet_destroy(handle); /* 释放句柄 */ + return -1; + }; + /* 构造IP协议块 */ + ip_tag = libnet_build_ipv4( + LIBNET_IPV4_H + LIBNET_TCP_H + payload_s, /* IP协议块的总长,*/ + 0, /* tos */ + (u_short) libnet_get_prand(LIBNET_PRu32), /* id,随机产生0~65535 */ + 0, /* frag 片偏移 */ + (u_int8_t)libnet_get_prand(LIBNET_PR8), /* ttl,随机产生0~255 */ + proto, /* 上层协议 */ + 0, /* 校验和,此时为0,表示由Libnet自动计算 */ + src_ip, /* 源IP地址,网络序 */ + dst_ip, /* 目标IP地址,网络序 */ + NULL, /* 负载内容或为NULL */ + 0, /* 负载内容的大小*/ + handle, /* Libnet句柄 */ + 0 /* 协议块标记可修改或创建,0表示构造一个新的*/ + ); + if (ip_tag == -1) { + printf("libnet_build_ipv4 failure\n"); + //libnet_destroy(handle); /* 释放句柄 */ + return -1; + }; + + record_start_time(nr); + ret = libnet_write(handle); /* 发送数据包*/ + //printf("packet_size:%d\n", ret); + if (ret < packet_size) { + printf("send tcp package failed:%d, errno:%s\n", packet_size, strerror(errno)); + //libnet_destroy(handle); /* 释放句柄 */ + return -1; + } + /* syn->ack 及时收发包 */ + usleep(1000 * trace_para.delay); + // 清除包,否则会有包过长问题 + libnet_clear_packet(handle); + seq++; + } + + //libnet_destroy(handle); /* 释放句柄 */ + return 0; +} + + +static void sig_handler(int sig) +{ + exiting = true; +} + +static void handle_event(void *ctx, int cpu, void *data, __u32 data_sz) +{ + struct tcptrace_map_value *trace = (struct tcptrace_map_value*)data; + int direction; + + for (int i = 0; i < PT_MAX; i++) { + if (trace->entries[i].ns) { + direction = trace->entries[i].padding; + switch (direction) { + case TCPTRACE_DIRECTION_OUT: + trace_time.time[trace_time.out_id].times[trace->entries[i].function_id] = trace->entries[i].ns; + break; + case TCPTRACE_DIRECTION_IN: + trace_time.time[trace_time.in_id].times[trace->entries[i].function_id] = trace->entries[i].ns; + break; + default: + printf("no direction:%d\n", direction); + break; + } + } +#ifdef DEBUG + printf("cpu:%d, func id:%d, timestamp:%lu, dire:%d, num:%d\n", cpu, trace->entries[i].function_id, + trace->entries[i].ns, trace->entries[i].padding, trace_time.out_id); +#endif + } + switch (direction) { + case TCPTRACE_DIRECTION_OUT: + trace_time.out_id++; + break; + case TCPTRACE_DIRECTION_IN: + if (trace_para.file) { + json_dump(trace_time.in_id); + } else { + image_show(trace_time.in_id); + } + trace_time.in_id++; + break; + default: + printf("no direaction,:%d\n", direction); + break; + } + // exit when receive last package + if (trace_time.in_id == trace_para.pack_nr) { + kill(getpid(), SIGINT); + } +} + +static void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt) +{ + printf("Lost %llu events on CPU %d\n", lost_cnt, cpu); +} + +static int trace(void) +{ + /* 初始化Libnet */ + if ((handle = libnet_init(LIBNET_RAW4, NULL, error)) == NULL) { + printf("libnet_init failure:%s\n", error); + return -1; + } + probe(trace_para.pack_nr, trace_para.tuple.src_ip, trace_para.tuple.dst_ip, + trace_para.tuple.src_port, trace_para.tuple.dst_port); + libnet_destroy(handle); /* 释放句柄 */ + + return 0; +} + +static void tcpping_event_printer(int perf_map_fd) +{ + int err; + struct perf_buffer_opts pb_opts = { + .sample_cb = handle_event, + .lost_cb = handle_lost_events, + }; + struct perf_buffer *pb = NULL; +#ifdef DEBUG + int i, j; +#endif + + pb = perf_buffer__new(perf_map_fd, 256, &pb_opts); + err = libbpf_get_error(pb); + if (err) { + pb = NULL; + printf("failed to open perf buffer: %d\n", err); + goto cleanup; + } + err = trace(); + if (err) { + goto cleanup; + } + /* polling the data */ + while (1) { + err = perf_buffer__poll(pb, 200); + if (err < 0 && errno != EINTR) { + printf("Error polling perf buffer: %d\n", err); + goto err; + } + if (exiting) + break; + } +#ifdef DEBUG + for (i = 0; i < trace_time.size; i++) { + printf("===========package:%d============\n", i); + for (j = 0; j < 10; j++) { + if (trace_time.time[i].times[j]) { + printf("func id:%d, timestamp:%llu, \n", j, trace_time.time[i].times[j]); + } + } + } +#endif + +err: + free(trace_time.time); + trace_time.time = NULL; +cleanup: + perf_buffer__free(pb); +} + +static int libbpf_print_fn(enum libbpf_print_level level, + const char *format, va_list args) +{ + return vfprintf(stderr, format, args); +} + +static void get_btf_path(void) +{ + FILE *fp = NULL; + char version[64] = {}; + char *sysak_env_path = NULL; + + fp = popen("uname -r", "r"); + if (!fp) { + printf("uname -r open failed, error:%s\n", strerror(errno)); + return; + } + fgets(version, sizeof(version), fp); + strcat(btf_path_buf, version); + + // get btf from sysak first + sysak_env_path = getenv("SYSAK_WORK_PATH"); + if (sysak_env_path) { + memset(btf_path_buf, 0, sizeof(btf_path_buf)); + snprintf(btf_path_buf, BTF_PATH_MAX, "%s/tools/vmlinux-btf/vmlinux-%s", sysak_env_path, version); + } + + btf_path_buf[strlen(btf_path_buf) - 1] = '\0'; +#ifdef DEBUG + printf("kernel version:%s, size:%ld\n", btf_path_buf, strlen(btf_path_buf)); +#endif + pclose(fp); +} + +static void tcpping_update_tuple_info(int fd, struct tuple_info *tuple) +{ + int err; + int key = 0; + + err = bpf_map_update_elem(fd, &key, tuple, 0); + if (err != 0) + fprintf(stderr, "bpf_map_update_ele error:%d %s", + errno, strerror(errno)); +} + +static void bump_memlock_rlimit(void) +{ + struct rlimit rlim_new = { + .rlim_cur = RLIM_INFINITY, + .rlim_max = RLIM_INFINITY, + }; + + if (setrlimit(RLIMIT_MEMLOCK, &rlim_new)) { + fprintf(stderr, "Failed to increase RLIMIT_MEMLOCK limit!\n"); + exit(1); + } +} + +static int is_numer(char *s) +{ + int i; + if (!s || !s[0]) + return 0; + for (i = 0; s[i]; i++) { + if (!isdigit((unsigned char)s[i])) + return 0; + } + return 1; +} + +static int para_parse(int argc, char **argv) +{ + int opt; + int err; + + while ((opt = getopt(argc, argv, "s:p:o:c:t:d:u:h")) != -1) { + switch (opt) { + case 'p': + if (!is_numer(optarg)) + return -1; + trace_para.tuple.src_port = atoi(optarg); + break; + case 'q': + if (!is_numer(optarg)) + return -1; + trace_para.tuple.dst_port = atoi(optarg); + break; + + case 's': + trace_para.tuple.src_ip = inet_addr(optarg); + break; + case 'd': + trace_para.tuple.dst_ip = inet_addr(optarg); + break; + case 'c': + if (!is_numer(optarg)) + return -1; + trace_para.pack_nr = atoi(optarg); + break; + case 'o': + /* + if (!is_numer(optarg)) + return -1; + trace_para.output_mode = atoi(optarg); + */ + if (optarg) { + err = trace_output_init(optarg); + if (err != 0) + return err; + } + break; + case 't': + if (!is_numer(optarg)) + return -1; + trace_para.delay = atoi(optarg); + break; + case 'u': + trace_para.cpu = atoi(optarg); + break; + + case 'h': + default: + fprintf(stderr, "Usage:[-d dip] [-s sip][-c package count] [-o output mode]\n"); + fprintf(stderr, "[-t send delay ms] [-p sport] [-q dport] [-u cpu affinity]\n"); + fprintf(stderr, "example sudo ./tcpping -s 11.160.62.45 -d 11.160.62.49 -c 10 -o /tmp/tcpping.json\n"); + exit(EXIT_FAILURE); + } + } + return 0; +} + +void set_cpu(int cpu) +{ + cpu_set_t mask; + CPU_ZERO(&mask); + CPU_SET(cpu, &mask); + sched_setaffinity(0, sizeof(cpu_set_t), &mask); +} + +int main(int argc, char **argv) +{ + struct tcpping_bpf *obj = NULL; + int err = 0; + + err = para_parse(argc, argv); + if (err) { + printf("parameter parse failed, err:%d\n", err); + goto cleanout; + } + + if (trace_para.cpu != -1) { + set_cpu(trace_para.cpu); + } + bump_memlock_rlimit(); + get_btf_path(); + libbpf_set_print(libbpf_print_fn); + //DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts); + //open_opts.btf_custom_path = btf_path_buf; + //open_opts.btf_custom_path = "/boot/vmlinux-4.19.91-007.ali4000.alios7.x86_64"; +#ifdef DEBUG + printf("%s, size:%ld\n", open_opts.btf_custom_path, + strlen(open_opts.btf_custom_path)); +#endif + //obj = tcpping_bpf__open_opts(&open_opts); + obj = tcpping_bpf__open(); + if (!obj) { + err = -1; + printf("failed to open BPF object\n"); + goto cleanout; + } + err = tcpping_bpf__load(obj); + if (err) { + printf("failed to load BPF object\n"); + goto cleanup; + } + err = tcpping_bpf__attach(obj); + if (err) { + printf("failed to attach BPF object\n"); + goto cleanup; + } + signal(SIGINT, sig_handler); + + tcpping_update_tuple_info(bpf_map__fd(obj->maps.tuple_map), + &trace_para.tuple); + + tcpping_event_printer(bpf_map__fd(obj->maps.perf_map)); + +cleanup: + tcpping_bpf__destroy(obj); +cleanout: + trace_output_close(); + return err; +} diff --git a/source/tools/detect/net_diag/tcpping/tcpping b/source/tools/detect/net_diag/tcpping/tcpping new file mode 100755 index 0000000000000000000000000000000000000000..d7c7a973a9fce9a31e2b4bdc3003ab8b7b529bc2 Binary files /dev/null and b/source/tools/detect/net_diag/tcpping/tcpping differ