├── test ├── config │ ├── empty.conf │ ├── routing-no-gateway.conf │ ├── single_udp_packet.pcap │ ├── CMakeLists.txt │ ├── icmp.conf │ ├── ioctl1.conf │ ├── udp.conf │ ├── routing-gateway.conf │ ├── rtnetlink-multiple-interfaces.conf │ ├── network.conf │ ├── tcp1.conf │ ├── tcp2.conf │ └── udp2.conf ├── gtest.cpp ├── udp │ ├── ipv4 │ │ ├── gtest.cpp │ │ ├── udp-ipv4.h │ │ ├── CMakeLists.txt │ │ ├── udp-ipv4-accept.cpp │ │ ├── udp-ipv4-shutdown.cpp │ │ └── udp-ipv4-send.cpp │ ├── udp2.cpp │ └── udp_connect.cpp ├── environment │ ├── rtnetlink │ │ ├── getlink │ │ │ ├── rtnetlink_getlink_test_helper.h │ │ │ ├── rtnetlink_getlink_test_helper.cpp │ │ │ ├── rtnetlink_getlink_single_device_filter.cpp │ │ │ ├── rtnetlink_getlink_single_device_no_filter.cpp │ │ │ └── rtnetlink_getlink_all_devices.cpp │ │ └── getaddr │ │ │ ├── rtnetlink_getaddr_single_interface.cpp │ │ │ └── rtnetlink_getaddr_filter.cpp │ ├── others │ │ ├── others.cpp │ │ ├── dup.cpp │ │ └── stdio.cpp │ └── routing │ │ └── routing.cpp ├── CMakeLists.txt ├── tcp │ └── tcp-poll.cpp ├── icmp │ └── ipv6 │ │ └── icmpv6.cpp └── module-pcap │ └── pcap.cpp ├── modules ├── module-afl │ ├── afl-denylist │ ├── wait-child.h │ ├── module-afl.h │ ├── module-afl-config.h │ ├── CMakeLists.txt │ ├── module-afl-config.c │ └── wait-child.c └── module-hello-world │ ├── CMakeLists.txt │ └── module.c ├── README.md ├── src ├── hooks │ ├── module-wrapper.c │ ├── hooks.h │ ├── models.h │ ├── native.h │ ├── hooks-stdio.c │ ├── native-syscalls-x86-64.c │ └── hooks-poll.c ├── sockets │ ├── sockets_dgram.h │ ├── sockopt.h │ ├── sockets_rtnetlink.h │ ├── sockets_stream.h │ ├── sockets.h │ ├── dup.c │ ├── stdio.c │ ├── network_types.h │ ├── poll.c │ ├── sockets_util.h │ └── sockets_dgram.c ├── environment │ ├── network_env.h │ ├── import_host.h │ ├── routing.h │ ├── fd_table.h │ ├── network_env.c │ ├── util.c │ ├── interfaces.h │ ├── fd_table.c │ ├── getifaddrs.c │ ├── routing.c │ └── ioctl.c ├── lib │ ├── libnl │ │ └── libnl.h │ └── logger │ │ └── log.c ├── init.c └── CMakeLists.txt ├── CMakeLists.txt ├── include └── netfuzzlib │ ├── types.h │ ├── log.h │ ├── util.h │ ├── module_api.h │ └── api.h └── cmake ├── compile_bitcode_library.cmake └── find_bitcode_compiler.cmake /test/config/empty.conf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/config/routing-no-gateway.conf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /modules/module-afl/afl-denylist: -------------------------------------------------------------------------------- 1 | module.c -------------------------------------------------------------------------------- /test/config/single_udp_packet.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeroenRobben/netfuzzlib/HEAD/test/config/single_udp_packet.pcap -------------------------------------------------------------------------------- /test/gtest.cpp: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | int main(int argc, char **argv) { 4 | ::testing::InitGoogleTest(&argc, argv); 5 | return RUN_ALL_TESTS(); 6 | } -------------------------------------------------------------------------------- /test/udp/ipv4/gtest.cpp: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | int main(int argc, char **argv) { 4 | ::testing::InitGoogleTest(&argc, argv); 5 | return RUN_ALL_TESTS(); 6 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Netfuzzlib 2 | 3 | Artifacts for the ESORICS 2024 paper "**Netfuzzlib: Adding First-Class Fuzzing Support to Network Protocol Implementations**". Further documentation and examples will be released later. 4 | -------------------------------------------------------------------------------- /modules/module-afl/wait-child.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_WAIT_CHILD_H 2 | #define NETFUZZLIB_WAIT_CHILD_H 3 | 4 | void wait_child_thread(); 5 | void init_wait_child(); 6 | 7 | void set_track_child_pids(bool track); 8 | 9 | #endif //NETFUZZLIB_WAIT_CHILD_H 10 | -------------------------------------------------------------------------------- /modules/module-afl/module-afl.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_AFL_H 2 | #define MODULE_AFL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int __afl_persistent_loop(unsigned int max_cnt); 11 | 12 | #endif //MODULE_AFL_H 13 | -------------------------------------------------------------------------------- /src/hooks/module-wrapper.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "netfuzzlib/module_api.h" 3 | 4 | void nfl_end_priv() { 5 | static void (*nfl_end_module)() = NULL; 6 | if (!nfl_end_module) 7 | nfl_end_module = dlsym(RTLD_NEXT, "nfl_end"); 8 | if (nfl_end_module) { 9 | (*nfl_end_module)(); 10 | } 11 | exit(0); 12 | } -------------------------------------------------------------------------------- /test/environment/rtnetlink/getlink/rtnetlink_getlink_test_helper.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_RTNETLINK_GETLINK_TEST_HELPER_CPP_H 2 | #define NETFUZZLIB_RTNETLINK_GETLINK_TEST_HELPER_CPP_H 3 | 4 | void test_link(const struct nlmsghdr *msg, const char *name, const char *hw_addr, const char *hw_broadcast_addr, int mtu, unsigned int flags); 5 | 6 | #endif //NETFUZZLIB_RTNETLINK_GETLINK_TEST_HELPER_CPP_H 7 | -------------------------------------------------------------------------------- /src/sockets/sockets_dgram.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_SOCKETS_DGRAM_H 2 | #define NETFUZZLIB_SOCKETS_DGRAM_H 3 | 4 | #include "network_types.h" 5 | 6 | int connect_dgram(nfl_sock_t *sock, const nfl_addr_t *addr, socklen_t addrlen); 7 | 8 | ssize_t recvmsg_dgram(nfl_sock_t *sock, struct msghdr *msg, int flags); 9 | 10 | ssize_t sendmsg_dgram(nfl_sock_t *sock, const struct msghdr *msg, int flags); 11 | 12 | #endif // NETFUZZLIB_SOCKETS_DGRAM_H 13 | -------------------------------------------------------------------------------- /src/sockets/sockopt.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_SOCKOPT_H 2 | #define NETFUZZLIB_SOCKOPT_H 3 | 4 | //Print an error message for a getsockopt call with given level and option_name 5 | void getsockopt_print_unsupported_error(int level, int option_name); 6 | 7 | //Print an error message for a setsockopt call with given level and option_name 8 | void setsockopt_print_unsupported_error(int level, int option_name); 9 | 10 | #endif // NETFUZZLIB_SOCKOPT_H 11 | -------------------------------------------------------------------------------- /test/udp/ipv4/udp-ipv4.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_UDP_IPV4_H 2 | #define NETFUZZLIB_UDP_IPV4_H 3 | 4 | #define BLACKHOLE_HOST 0x08080808 5 | #define BLACKHOLE_PORT 53 6 | 7 | #define errx(code, fmt, ...) \ 8 | do { \ 9 | FAIL() << fmt; \ 10 | } while (0) 11 | 12 | #define warn(...) \ 13 | do { \ 14 | } while (0) 15 | 16 | #define warnx(...) \ 17 | do { \ 18 | } while (0) 19 | 20 | #endif //NETFUZZLIB_UDP_IPV4_H 21 | -------------------------------------------------------------------------------- /src/sockets/sockets_rtnetlink.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_SOCKETS_RTNETLINK_H 2 | #define NETFUZZLIB_SOCKETS_RTNETLINK_H 3 | 4 | #include "network_types.h" 5 | 6 | typedef struct netlink_msg_ll { 7 | struct nl_msg *msg; 8 | struct netlink_msg_ll *next; 9 | } netlink_msg_ll; 10 | 11 | ssize_t recvmsg_netlink(nfl_sock_t *socket, struct msghdr *msg, int flags); 12 | 13 | ssize_t sendmsg_netlink(nfl_sock_t *socket, const struct msghdr *msg, int flags); 14 | 15 | #endif // NETFUZZLIB_SOCKETS_RTNETLINK_H 16 | -------------------------------------------------------------------------------- /test/config/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CONF_FILES 2 | empty.conf 3 | icmp.conf 4 | ioctl1.conf 5 | network.conf 6 | routing-gateway.conf 7 | routing-no-gateway.conf 8 | rtnetlink-multiple-interfaces.conf 9 | tcp1.conf 10 | tcp2.conf 11 | udp.conf 12 | udp2.conf 13 | single_udp_packet.pcap) 14 | 15 | foreach(CONF_FILE ${CONF_FILES}) 16 | configure_file(${CONF_FILE} ${CMAKE_CURRENT_BINARY_DIR}/${CONF_FILE} COPYONLY) 17 | endforeach() 18 | -------------------------------------------------------------------------------- /test/config/icmp.conf: -------------------------------------------------------------------------------- 1 | packet-format icmpv6-test { 2 | uint8: 0x12 //Concrete 3 | char[10]: //Symbolic 4 | } 5 | 6 | 7 | incoming-config queue-icmpv6-1 { 8 | device-name: klee-lo 9 | domain: AF_INET6 10 | type: SOCK_RAW 11 | protocol: IPPROTO_ICMPV6 12 | receiver-ip: ::1 13 | sender-ip: fe80::dde7:5fd2:1f80:3d7e 14 | packet-queue: icmpv6-test 15 | } 16 | 17 | device klee-lo { 18 | flags: 4163 # see man 7 netdevice #SIOCGIFFLAGS 19 | mac: 50:eb:71:56:ab:9e 20 | mac-broadcast: ff:ff:ff:ff:ff:ff 21 | mtu: 1500 22 | address-ipv4: { 23 | address: 127.0.0.1 24 | netmask: 255.255.255.0 25 | } 26 | address-ipv6: { 27 | address: ::1 28 | prefix: 64 29 | } 30 | } -------------------------------------------------------------------------------- /modules/module-afl/module-afl-config.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_AFL_CONFIG_H 2 | #define MODULE_AFL_CONFIG_H 3 | #include 4 | #include 5 | #include 6 | 7 | enum tcp_mode { SUT_IS_CLIENT = 1, SUT_IS_SERVER = 0 }; 8 | 9 | typedef struct afl_module_config { 10 | uint32_t protocol; 11 | nfl_addr_t addr_fuzzer; 12 | nfl_addr_t addr_sut; 13 | enum tcp_mode tcp_mode; 14 | bool stop_fuzzing; 15 | bool persistent_mode; 16 | 17 | } afl_module_config; 18 | 19 | afl_module_config *get_module_config(); 20 | nfl_pkt *get_static_packet(); 21 | 22 | int load_config(); 23 | int load_config_ip_sut(); 24 | int load_config_ipv4(int sut_port); 25 | int load_config_ipv6(int sut_port); 26 | 27 | #endif //MODULE_AFL_CONFIG_H 28 | -------------------------------------------------------------------------------- /src/sockets/sockets_stream.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_SOCKETS_STREAM_H 2 | #define NETFUZZLIB_SOCKETS_STREAM_H 3 | 4 | #include "network_types.h" 5 | 6 | int connect_stream(nfl_sock_t *sock, const nfl_addr_t *remote_addr, socklen_t addrlen); 7 | 8 | /** 9 | * Update the pending connections of a listening socket. This will invoke the fuzzing module if no current pending 10 | * connection exists. 11 | * @param listening_socket The listening socket 12 | * @return 0 on success, -1 on error 13 | */ 14 | int tcp_update_pending_connections(nfl_sock_t *listening_socket); 15 | 16 | ssize_t recvmsg_stream(nfl_sock_t *sock, struct msghdr *msg, int flags); 17 | 18 | ssize_t sendmsg_stream(nfl_sock_t *sock, const struct msghdr *msg, int flags); 19 | 20 | #endif // NETFUZZLIB_SOCKETS_STREAM_H 21 | -------------------------------------------------------------------------------- /src/environment/network_env.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_NETWORK_ENV_H 2 | #define NETFUZZLIB_NETWORK_ENV_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "sockets/network_types.h" 13 | #include "sockets/sockets_rtnetlink.h" 14 | 15 | #define NFL_FD_DEV_NULL NFL_RESERVED_FD_START 16 | #define NFL_FD_LOG (NFL_RESERVED_FD_START + 1) 17 | 18 | /** 19 | * Initialize the netfuzzlib main library 20 | * @return 0 on success, -1 on failure 21 | */ 22 | int init_main_library(); 23 | 24 | /* 25 | * Get the current global network environment 26 | */ 27 | network_env *get_network_env(); 28 | 29 | #endif // NETFUZZLIB_NETWORK_ENV_H 30 | -------------------------------------------------------------------------------- /test/config/ioctl1.conf: -------------------------------------------------------------------------------- 1 | device klee-lo { #klee-lo 2 | flags: 73 # 3 | mac: 50:00:00:00:00:00 4 | mac-broadcast: ff:ff:ff:ff:ff:ff 5 | mtu: 65536 6 | address-ipv4: { 7 | address: 127.0.0.1 8 | netmask: 255.0.0.0 9 | } 10 | address-ipv6: { 11 | address: ::1 12 | prefix: 128 13 | } 14 | } 15 | 16 | device klee-eth0 { #klee-eth0 17 | flags: 4163 18 | mac: 50:aa:00:00:00:00 19 | mac-broadcast: ff:ff:ff:ff:ff:ff 20 | mtu: 1500 21 | address-ipv4: { 22 | address: 192.168.1.2 23 | netmask: 255.255.255.0 24 | } 25 | address-ipv6: { 26 | address: fe80::5859:71af:177e:db7a 27 | prefix: 64 28 | } 29 | address-ipv6: { 30 | address: 2a02::0:ab43:c679 31 | prefix: 64 32 | } 33 | } -------------------------------------------------------------------------------- /test/config/udp.conf: -------------------------------------------------------------------------------- 1 | packet-format packet-1 { 2 | uint8: 0x12 //Concrete 3 | char[10]: //Symbolic 4 | } 5 | 6 | packet-format packet-2 { 7 | uint32: 1111111 8 | } 9 | 10 | packet-format packet-3 { 11 | uint8: 100 12 | uint16: 13 | uint32: 123456 14 | } 15 | 16 | incoming-config queue-test-1 { 17 | device-name: lo 18 | domain: AF_INET 19 | type: SOCK_DGRAM 20 | protocol: IPPROTO_UDP 21 | receiver-ip: 127.0.0.1 22 | sender-ip: 127.0.0.2 23 | receiver-port: 5000 24 | sender-port: 5001 25 | packet-queue: packet-1 packet-2 26 | } 27 | 28 | incoming-config queue-test-2 { 29 | device-name: lo 30 | domain: AF_INET6 31 | type: SOCK_DGRAM 32 | protocol: IPPROTO_UDP 33 | receiver-ip: ::1 34 | sender-ip: ::2 35 | receiver-port: 6000 36 | sender-port: 6001 37 | packet-queue: packet-3 38 | } -------------------------------------------------------------------------------- /src/lib/libnl/libnl.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_LIBNL_H 2 | #define NETFUZZLIB_LIBNL_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define NLE_NOMEM 5 11 | #define NLE_INVAL 7 12 | 13 | struct nl_msg { 14 | struct nlmsghdr *nm_nlh; 15 | size_t nm_size; 16 | int nm_refcnt; 17 | }; 18 | 19 | struct nl_msg *nlmsg_alloc(); 20 | void nlmsg_free(struct nl_msg *msg); 21 | 22 | int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad); 23 | struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, int flags); 24 | struct nlmsghdr *nlmsg_hdr(struct nl_msg *); 25 | 26 | int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data); 27 | 28 | #endif // NETFUZZLIB_LIBNL_H 29 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | project(netfuzzlib C CXX) 3 | 4 | set(CMAKE_C_STANDARD 11) 5 | set(CMAKE_CXX_STANDARD 11) 6 | 7 | add_compile_definitions(_GNU_SOURCE) 8 | add_compile_options(-g) 9 | add_link_options(-g -ldl) 10 | 11 | if(CMAKE_BUILD_TYPE STREQUAL "Debug") 12 | add_compile_definitions(NFL_DEBUG) 13 | endif () 14 | 15 | include_directories(include) 16 | include_directories(src) 17 | 18 | include(cmake/find_bitcode_compiler.cmake) 19 | include(cmake/compile_bitcode_library.cmake) 20 | 21 | 22 | add_subdirectory(test) 23 | add_subdirectory(src) 24 | add_subdirectory(modules/module-config-file) 25 | add_subdirectory(modules/module-hello-world) 26 | add_subdirectory(modules/module-pcap) 27 | add_subdirectory(modules/module-afl) 28 | add_subdirectory(modules/module-aflnet) 29 | add_subdirectory(modules/module-aflnet-replay) 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /test/config/routing-gateway.conf: -------------------------------------------------------------------------------- 1 | device device-1-eth0 { 2 | flags: 4163 3 | mac: 50:aa:00:00:00:00 4 | mac-broadcast: ff:ff:ff:ff:ff:ff 5 | mtu: 1500 6 | address-ipv4: { 7 | address: 192.168.1.2 8 | netmask: 255.255.255.0 9 | } 10 | address-ipv4: { 11 | address: 91.34.10.2 12 | netmask: 255.255.255.255 13 | } 14 | address-ipv6: { 15 | gateway-address: 2a02::0:ab43:c678 16 | address: 2a02::0:ab43:c679 17 | prefix: 64 18 | } 19 | } 20 | 21 | device device-2-eth1 { 22 | flags: 4163 23 | mac: 60:aa:00:00:00:00 24 | mac-broadcast: ff:ff:ff:ff:ff:ff 25 | mtu: 1500 26 | address-ipv4: { 27 | gateway-address: 10.0.0.1 28 | address: 10.0.0.5 29 | netmask: 255.0.0.0 30 | } 31 | address-ipv6: { 32 | address: 2a02::3183:a900:5b63:0019:ab00:c679 33 | prefix: 64 34 | } 35 | address-ipv6: { 36 | address: fe80::5859:71af:177e:db7a 37 | prefix: 32 38 | } 39 | } -------------------------------------------------------------------------------- /modules/module-afl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | project(module-pcap C) 3 | set(CMAKE_C_STANDARD 11) 4 | 5 | add_compile_definitions(_GNU_SOURCE) 6 | 7 | set(SRC_FILES 8 | module-afl.c 9 | module-afl-config.c 10 | ) 11 | 12 | add_library(module-afl SHARED ${SRC_FILES}) 13 | target_include_directories(module-afl PUBLIC ${CMAKE_SOURCE_DIR}/modules/include include) 14 | 15 | add_library(module-afl-static STATIC ${SRC_FILES}) 16 | target_include_directories(module-afl-static PUBLIC ${CMAKE_SOURCE_DIR}/modules/include include) 17 | 18 | add_library(module-afl-static-debug STATIC ${SRC_FILES}) 19 | target_compile_definitions(module-afl-static-debug PUBLIC DEBUG) 20 | target_include_directories(module-afl-static-debug PUBLIC ${CMAKE_SOURCE_DIR}/modules/include include) 21 | 22 | add_library(module-afl-debug SHARED ${SRC_FILES}) 23 | target_compile_definitions(module-afl-debug PUBLIC DEBUG) 24 | target_include_directories(module-afl-debug PUBLIC ${CMAKE_SOURCE_DIR}/modules/include include) 25 | 26 | -------------------------------------------------------------------------------- /src/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "netfuzzlib/module_api.h" 3 | #include "environment/network_env.h" 4 | 5 | #ifndef INITIALIZE_NETWORK_MODEL_MANUAL 6 | void nfl_init_manual() __attribute__((constructor(0))); 7 | #endif 8 | 9 | void nfl_init_manual() { 10 | if (getenv("NETFUZZLIB_MANUAL_INIT")) { 11 | return; 12 | } 13 | nfl_init_logging(getenv("NETWORK_LOG_FILE")); 14 | 15 | int err = init_main_library(); 16 | 17 | if (err) { 18 | nfl_exit_log(1, "Error initializing network environment."); 19 | } 20 | #ifndef MODULE_STATIC_LINKED 21 | if (!dlsym(RTLD_DEFAULT, "nfl_initialize")) { 22 | nfl_exit_log(1, "Function nfl_initialize() was not linked, probably no module is present in the linker path."); 23 | } 24 | #endif 25 | if (!getenv("NETWORK_MODEL_MODULE_MANUAL_INIT")) { 26 | nfl_log_debug("Initializing fuzzing module"); 27 | err = nfl_initialize(); 28 | if (err) { 29 | nfl_exit_log(1, "Error initializing fuzzing module."); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/environment/import_host.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_IMPORT_HOST_H 2 | #define NETFUZZLIB_IMPORT_HOST_H 3 | #include "sockets/network_types.h" 4 | 5 | #define PROC_NET_IF_INET6 "/proc/net/if_inet6" 6 | #define PROC_NET_ROUTE "/proc/net/route" 7 | #define PROC_NET_IPV6_ROUTE "/proc/net/ipv6_route" 8 | #define SYS_CLASS_NET "/sys/class/net/" 9 | #define SYS_CLASS_NET_MTU "/sys/class/net/%s/mtu" 10 | #define SYS_CLASS_NET_FLAGS "/sys/class/net/%s/flags" 11 | #define SYS_CLASS_NET_INDEX "/sys/class/net/%s/ifindex" 12 | #define SYS_CLASS_NET_HW_ADDRESS "/sys/class/net/%s/address" 13 | #define SYS_CLASS_NET_HW_ADDRESS_LEN "/sys/class/net/%s/addr_len" 14 | #define SYS_CLASS_NET_HW_ADDRESS_BROADCAST "/sys/class/net/%s/broadcast" 15 | 16 | /* 17 | * Add a copy of the systems network l2_interfaces and l3_interfaces to the network environment. 18 | * This reduces the chance of discrepancies between the modelled network environment 19 | * and possible calls to the OS which are not modelled (e.g. interaction with NETLINK) 20 | */ 21 | void import_host_network_devices(); 22 | 23 | #endif // NETFUZZLIB_IMPORT_HOST_H 24 | -------------------------------------------------------------------------------- /src/sockets/sockets.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_SOCKETS_COMMON_H 2 | #define NETFUZZLIB_SOCKETS_COMMON_H 3 | 4 | #include "../environment/network_env.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /* 16 | * Return whether a given combination of socket domain, type and protocol is supported by the model. 17 | * See man 2 socket 18 | */ 19 | bool is_socket_supported(int domain, int type, int protocol); 20 | 21 | uint16_t get_ephemeral_local_port_network_byte_order(); 22 | 23 | /* 24 | * Used when calling connect() without a prior bind call 25 | * First check whether the target address to connect to is in the local subnet of an existing device address. 26 | * If this is the case, bind to the address of this interface. 27 | * Otherwise, bind to the address of the default gateway. 28 | * Always use a random ephemeral port. 29 | */ 30 | int autobind_udp(nfl_sock_t *socket, const nfl_addr_t *remote_addr); 31 | 32 | #endif /*NETFUZZLIB_SOCKETS_COMMON_H*/ -------------------------------------------------------------------------------- /test/config/rtnetlink-multiple-interfaces.conf: -------------------------------------------------------------------------------- 1 | device device-1-no-l3 { 2 | flags: 73 # 3 | mac: 60:00:00:00:00:00 4 | mac-broadcast: ff:ff:ff:ff:ff:ff 5 | mtu: 65536 6 | } 7 | 8 | device device-2-eth0 { 9 | flags: 4163 10 | mac: 50:aa:00:00:00:00 11 | mac-broadcast: ff:ff:ff:ff:ff:ff 12 | mtu: 1500 13 | address-ipv4: { 14 | address: 192.168.1.2 15 | netmask: 255.255.255.0 16 | } 17 | address-ipv4: { 18 | address: 91.34.10.2 19 | netmask: 255.255.255.255 20 | } 21 | address-ipv6: { 22 | address: 2a02::0:ab43:c679 23 | prefix: 64 24 | } 25 | } 26 | 27 | device device-3-eth1 { 28 | flags: 4163 29 | mac: 60:aa:00:00:00:00 30 | mac-broadcast: ff:ff:ff:ff:ff:ff 31 | mtu: 1500 32 | address-ipv4: { 33 | address: 10.0.0.5 34 | netmask: 255.0.0.0 35 | } 36 | address-ipv4: { 37 | address: 91.34.10.2 38 | netmask: 255.255.255.255 39 | } 40 | address-ipv6: { 41 | address: 2a02::3183:a900:5b63:0019:ab00:c679 42 | prefix: 64 43 | } 44 | address-ipv6: { 45 | address: fe80::5859:71af:177e:db7a 46 | prefix: 32 47 | } 48 | } -------------------------------------------------------------------------------- /include/netfuzzlib/types.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_TYPES_H 2 | #define NETFUZZLIB_TYPES_H 3 | #include 4 | #include 5 | #include 6 | 7 | typedef union { 8 | struct sockaddr s; 9 | struct sockaddr_in s4; 10 | struct sockaddr_in6 s6; 11 | struct sockaddr_nl nl; 12 | } nfl_addr_t; 13 | 14 | /** 15 | * A network packet 16 | */ 17 | typedef struct nfl_pkt { 18 | struct iovec iov; // Iovec structure representing the contents of this packet. 19 | 20 | unsigned int device_index; // The index of the device by which this packet was received. Ignored for TCP packets. 21 | nfl_addr_t local_addr; // The receiver address of this packet, e.g. 255.255.255.255. Ignored for TCP packets. 22 | nfl_addr_t remote_addr; // The sender address of this packet, e.g. 255.255.255.255. Ignored for TCP packets. 23 | struct nfl_pkt *next; 24 | } nfl_pkt; 25 | 26 | typedef struct nfl_sock_module_t { 27 | int domain; // Network domain of the socket, AF_INET | AF_INET6 28 | int type; // Socket type, SOCK_DGRAM | SOCK_STREAM | SOCK_RAW 29 | int protocol; // Socket protocol, IPPROTO_UDP | IPPROTO_TCP | IPPROTO_ICMP | IPPROTO_ICMPV6 30 | } nfl_sock_module_t; 31 | 32 | #endif //NETFUZZLIB_TYPES_H 33 | -------------------------------------------------------------------------------- /modules/module-hello-world/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | project(module-hello-world C) 3 | set(CMAKE_C_STANDARD 11) 4 | 5 | add_compile_definitions(_GNU_SOURCE) 6 | 7 | add_library(module-hello-world SHARED module.c) 8 | target_compile_options(module-hello-world PUBLIC -g) 9 | target_link_options(module-hello-world PUBLIC -g) 10 | target_include_directories(module-hello-world PUBLIC ${CMAKE_SOURCE_DIR}/modules/include include) 11 | 12 | add_library(module-hello-world-static STATIC module.c) 13 | target_include_directories(module-hello-world-static PUBLIC ${CMAKE_SOURCE_DIR}/modules/include include) 14 | 15 | check_include_file("klee/klee.h" HAVE_KLEE) 16 | if(HAVE_KLEE) 17 | set(LIB_CFLAGS 18 | -D_FORTIFY_SOURCE=0 19 | -D_GNU_SOURCE 20 | -Wall 21 | -Wwrite-strings 22 | -Xclang 23 | -disable-O0-optnone 24 | -I${CMAKE_SOURCE_DIR}/modules/include 25 | -I${CMAKE_CURRENT_SOURCE_DIR}/include 26 | -DKLEE_ENABLED 27 | -g) 28 | add_bitcode_library_targets(module-hello-world-klee "${CMAKE_CURRENT_SOURCE_DIR}/module.c" "${LIB_CFLAGS}") 29 | else() 30 | message(WARNING "Could not find klee/klee.h, disabling target module-hello-world-klee") 31 | endif() 32 | -------------------------------------------------------------------------------- /include/netfuzzlib/log.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_LOG_H 2 | #define NETFUZZLIB_LOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | enum { NETFUZZLIB_LOG_TRACE, NETFUZZLIB_LOG_DEBUG, NETFUZZLIB_LOG_INFO, NETFUZZLIB_LOG_WARN, NETFUZZLIB_LOG_ERROR, NETFUZZLIB_LOG_FATAL }; 10 | 11 | #ifdef NFL_DEBUG 12 | #define nfl_log_trace(...) nfl_log_log(NETFUZZLIB_LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) 13 | #define nfl_log_debug(...) nfl_log_log(NETFUZZLIB_LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) 14 | #define nfl_log_info(...) nfl_log_log(NETFUZZLIB_LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) 15 | #define nfl_log_warn(...) nfl_log_log(NETFUZZLIB_LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) 16 | #define nfl_log_error(...) nfl_log_log(NETFUZZLIB_LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) 17 | #define nfl_log_fatal(...) nfl_log_log(NETFUZZLIB_LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) 18 | #else 19 | #define nfl_log_trace(...) 20 | #define nfl_log_debug(...) 21 | #define nfl_log_info(...) 22 | #define nfl_log_warn(...) 23 | #define nfl_log_error(...) 24 | #define nfl_log_fatal(...) 25 | #endif 26 | 27 | void nfl_log_log(int level, const char *file, int line, const char *fmt, ...); 28 | 29 | void nfl_init_logging(char *logfile_path); 30 | 31 | #endif //NETFUZZLIB_LOG_H 32 | -------------------------------------------------------------------------------- /test/udp/ipv4/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRC_FILES 2 | gtest.cpp 3 | 4 | udp-ipv4-accept.cpp 5 | udp-ipv4-bind.cpp 6 | udp-ipv4-connect.cpp 7 | udp-ipv4-others.cpp 8 | udp-ipv4-pair.cpp 9 | udp-ipv4-send.cpp 10 | udp-ipv4-shutdown.cpp 11 | udp-ipv4-trio.cpp) 12 | 13 | set(KERNEL_TEST_RENAME 14 | TestUDPv4Accept=TestUDPIpv4AcceptKernel 15 | TestUDPv4Bind=TestUDPIpv4BindKernel 16 | TestUDPv4Connect=TestUDPIpv4ConnectKernel 17 | TestUDPv4Others=TestUDPIpv4OthersKernel 18 | TestUDPv4Pair=TestUDPIpv4PairKernel 19 | TestUDPv4Send=TestUDPIpv4SendKernel 20 | TestUDPv4Shutdown=TestUDPIpv4ShutdownKernel 21 | TestUDPv4Trio=TestUDPIpv4TrioKernel) 22 | 23 | 24 | add_executable(runUnitTestsUdpIpv4 ${SRC_FILES}) 25 | target_link_libraries(runUnitTestsUdpIpv4 gtest gmock netfuzzlib module-config-file-unittest) 26 | gtest_add_tests(runUnitTestsUdpIpv4 "" AUTO) 27 | 28 | #add_executable(runUnitTestsUdpIpv4Kernel ${SRC_FILES}) 29 | #target_link_libraries(runUnitTestsUdpIpv4Kernel gtest gmock) 30 | #target_compile_definitions(runUnitTestsUdpIpv4Kernel PRIVATE TEST_KERNEL) 31 | #target_compile_definitions(runUnitTestsUdpIpv4Kernel PRIVATE ${KERNEL_TEST_RENAME}) 32 | #gtest_add_tests(runUnitTestsUdpIpv4Kernel "" AUTO) 33 | -------------------------------------------------------------------------------- /test/config/network.conf: -------------------------------------------------------------------------------- 1 | packet-format icmp { 2 | uint8: 0x12 3 | char[50]: 4 | } 5 | 6 | 7 | packet-format dhcp { 8 | uint8: 0x12 9 | char[50] 10 | uint16: 11 | uint32: 500 12 | } 13 | 14 | incoming-config dhcp-ipv6 { 15 | domain: AF_INET6 16 | type: SOCK_STREAM # SOCK_RAW / SOCK_DGRAM / SOCK_STREAM 17 | protocol: IPPROTO_TCP #IPPROTO_TCP, IPPROTO_UDP, IPPROTO_ICMP 18 | stream-connection-mode: accept #OUTGOING INCOMING 19 | receiver-ip: ::1 20 | sender-ip: ::1 21 | receiver-port: 5000 22 | sender-port: 5000 23 | packet-queue: dhcp 24 | device-name: lo 25 | } 26 | 27 | incoming-config dhcp-ipv4 { 28 | domain: AF_INET 29 | type: SOCK_RAW # SOCK_RAW / SOCK_DGRAM / SOCK_RAW 30 | protocol: IPPROTO_ICMP #IPPROTO_TCP, IPPROTO_UDP, IPPROTO_ICMP 31 | receiver-ip: 127.0.0.1 32 | sender-ip: 127.0.0.1 33 | receiver-port: 5000 34 | sender-port: 5000 35 | device-name:lo 36 | packet-queue: dhcp icmp icmp dhcp 37 | } 38 | 39 | device klee-lo { 40 | flags: 4163 # see man 7 netdevice #SIOCGIFFLAGS 41 | mac: 50:eb:71:56:ab:9e 42 | mac-broadcast: ff:ff:ff:ff:ff:ff 43 | mtu: 1500 44 | address-ipv4: { 45 | address: 127.0.0.1 46 | netmask: 255.255.255.0 47 | } 48 | address-ipv6: { 49 | address: ::1 50 | prefix: 64 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/environment/routing.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_ROUTING_H 2 | #define NETFUZZLIB_ROUTING_H 3 | 4 | #include "sockets/network_types.h" 5 | 6 | /** 7 | * Get the local interface which would be used for sending a packet to a given destination 8 | * @param dest_addr The destination address of the packet. Port is ignored 9 | * @return A pointer to the nfl_l3_iface_t which would be used as outgoing interface for the packet, or NULL if no route to dest_addr exists 10 | */ 11 | nfl_l3_iface_t *routing_table_lookup(const nfl_addr_t *dest_addr); 12 | 13 | /** 14 | * Get the local interface which would be used for sending a packet to a given destination 15 | * @param dest_addr The destination address of the packet 16 | * @return A pointer to the nfl_l3_iface_t which would be used as outgoing interface for the packet, or NULL if no route to dest_addr exists 17 | */ 18 | nfl_l3_iface_t *routing_table_lookup_ipv4(const struct in_addr *dest_addr); 19 | 20 | /** 21 | * Get the local interface which would be used for sending a packet to a given destination 22 | * @param dest_addr The destination address of the packet 23 | * @return A pointer to the nfl_l3_iface_t which would be used as outgoing interface for the packet, or NULL if no route to dest_addr exists 24 | */ 25 | nfl_l3_iface_t *routing_table_lookup_ipv6(const struct in6_addr *dest_addr); 26 | 27 | #endif //NETFUZZLIB_ROUTING_H 28 | -------------------------------------------------------------------------------- /src/sockets/dup.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "hooks/models.h" 5 | #include "environment/network_env.h" 6 | #include "hooks/native.h" 7 | #include "environment/fd_table.h" 8 | 9 | int dup_nfl_fd(int oldfd) { 10 | nfl_sock_t *sock_oldfd = get_nfl_sock(oldfd); 11 | if (!sock_oldfd) { 12 | errno = EBADF; 13 | return -1; 14 | } 15 | return dup_nfl_sock(sock_oldfd); 16 | } 17 | 18 | int dup_nfl_sock(nfl_sock_t *old_sock) { 19 | int newfd = get_available_fd(); 20 | if (newfd < 0) { 21 | errno = EMFILE; 22 | return -1; 23 | } 24 | fd_table_set(newfd, old_sock); 25 | return newfd; 26 | } 27 | 28 | int dup2_nfl(int oldfd, int newfd) { 29 | if (oldfd == newfd || !is_nfl_sock_fd(oldfd) || newfd < 0) { 30 | errno = EINVAL; 31 | return -1; 32 | } 33 | if (newfd >= SOCKET_FD_MAX) { 34 | nfl_exit_log(1, "dup2_nfl: newfd >= SOCKET_FD_MAX"); 35 | } 36 | nfl_sock_t *sock_oldfd = get_nfl_sock(oldfd); 37 | if (get_nfl_sock(newfd)) { 38 | close_nfl_fd(newfd); 39 | } 40 | fd_table_set(newfd, sock_oldfd); 41 | dup2_native(get_network_env()->fd_dev_null, 42 | newfd); //Reserve the new fd; 43 | return newfd; 44 | } 45 | 46 | int dup3_nfl(int oldfd, int newfd, int flags) { 47 | return dup2_nfl(oldfd, newfd); 48 | } -------------------------------------------------------------------------------- /test/config/tcp1.conf: -------------------------------------------------------------------------------- 1 | packet-format packet1 { 2 | uint8: 0x05 3 | } 4 | 5 | packet-format packet2 { 6 | uint8: 0x06 7 | uint8: 0x10 8 | uint8: 0xaa 9 | } 10 | 11 | incoming-config tcp-queue-connect-ipv6 { 12 | domain: AF_INET6 13 | type: SOCK_STREAM 14 | protocol: IPPROTO_TCP 15 | stream-connection-mode: connect 16 | receiver-ip: ::1 17 | sender-ip: 2001:db88:3333:4444:5555:6666:7777:6666 18 | receiver-port: 6000 19 | sender-port: 7000 20 | device-name: lo 21 | packet-queue: packet1 packet2 22 | } 23 | 24 | 25 | incoming-config tcp-queue-accept-ipv6 { 26 | domain: AF_INET6 27 | type: SOCK_STREAM 28 | protocol: IPPROTO_TCP 29 | stream-connection-mode: accept 30 | receiver-ip: ::1 31 | sender-ip: 2001:db88:3333:4444:5555:6666:7777:8888 32 | receiver-port: 6000 33 | sender-port: 7001 34 | device-name: lo 35 | packet-queue: packet2 packet1 36 | } 37 | 38 | incoming-config tcp-queue-connect-ipv4 { 39 | domain: AF_INET 40 | type: SOCK_STREAM 41 | protocol: IPPROTO_TCP 42 | stream-connection-mode: connect 43 | receiver-ip: 127.0.0.1 44 | sender-ip: 127.0.0.5 45 | sender-port: 5000 46 | device-name: lo 47 | packet-queue: packet2 48 | } 49 | 50 | incoming-config tcp-queue-accept-ipv4 { 51 | domain: AF_INET 52 | type: SOCK_STREAM 53 | protocol: IPPROTO_TCP 54 | stream-connection-mode: accept 55 | receiver-ip: 127.0.0.1 56 | sender-ip: 127.0.0.5 57 | receiver-port: 4000 58 | sender-port: 5000 59 | device-name: lo 60 | packet-queue: packet1 61 | } -------------------------------------------------------------------------------- /test/config/tcp2.conf: -------------------------------------------------------------------------------- 1 | packet-format packet1 { 2 | uint8: 0x06 3 | uint8: 0x10 4 | uint8: 0xaa 5 | } 6 | 7 | 8 | packet-format packet2 { 9 | uint8: 0x01 10 | uint8: 0x02 11 | uint8: 0x04 12 | uint8: 0x0a 13 | uint8: 0x07 14 | uint8: 0x09 15 | } 16 | 17 | incoming-config tcp-queue-connect-ipv4 { 18 | domain: AF_INET 19 | type: SOCK_STREAM 20 | protocol: IPPROTO_TCP 21 | stream-connection-mode: connect 22 | receiver-ip: 127.0.0.1 23 | sender-ip: 127.0.0.5 24 | sender-port: 5000 25 | device-name: lo 26 | packet-queue: packet1 27 | } 28 | 29 | incoming-config tcp-queue-connect-ipv4-2 { 30 | domain: AF_INET 31 | type: SOCK_STREAM 32 | protocol: IPPROTO_TCP 33 | stream-connection-mode: connect 34 | receiver-ip: 127.0.0.1 35 | sender-ip: 127.0.0.5 36 | sender-port: 8000 37 | device-name: lo 38 | packet-queue: packet2 39 | } 40 | 41 | 42 | incoming-config tcp-queue-accept-ipv4 { 43 | domain: AF_INET 44 | type: SOCK_STREAM 45 | protocol: IPPROTO_TCP 46 | stream-connection-mode: accept 47 | receiver-ip: 127.0.0.1 48 | sender-ip: 127.0.0.5 49 | receiver-port: 2000 50 | sender-port: 5000 51 | device-name: lo 52 | packet-queue: packet1 53 | } 54 | 55 | incoming-config tcp-queue-accept-ipv4-2 { 56 | domain: AF_INET 57 | type: SOCK_STREAM 58 | protocol: IPPROTO_TCP 59 | stream-connection-mode: accept 60 | receiver-ip: 127.0.0.1 61 | sender-ip: 127.0.0.5 62 | receiver-port: 2000 63 | sender-port: 5001 64 | device-name: lo 65 | packet-queue: packet1 66 | } -------------------------------------------------------------------------------- /include/netfuzzlib/util.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_UTIL_H 2 | #define NETFUZZLIB_UTIL_H 3 | 4 | /** 5 | * Get the size of a sockaddr_in or sockaddr_in6 struct 6 | * @param domain The domain of the socket, AF_INET | AF_INET6 7 | * @return The size of the sockaddr struct 8 | */ 9 | socklen_t get_socket_domain_addrlen(int domain); 10 | 11 | /** 12 | * Check if an address is the zero address (0.0.0.0 | ::0) 13 | * @param addr The address to check 14 | * @return True iff the address is the zero address 15 | */ 16 | bool addr_is_zero_address(const nfl_addr_t *addr); 17 | 18 | /** 19 | * Check if two IP endpoints match. This is the case if both sockets are of the same IP version (4 | 6), both port numbers are equal 20 | * and both IP addresses are equal OR the zero address (0.0.0.0 | ::0) 21 | * @param addr1 The first endpoint 22 | * @param addr2 The second endpoint 23 | * @return True iff the endpoints match 24 | */ 25 | bool ip_endpoints_match(const nfl_addr_t *addr1, const nfl_addr_t *addr2); 26 | 27 | /** 28 | * Get the total amount of bytes in an iovec array 29 | * @param iov The iovec array 30 | * @param iovlen The amount of iovec structs in the array 31 | * @return The total amount of bytes in the array 32 | */ 33 | ssize_t iov_count_bytes(struct iovec *iov, size_t iovlen); 34 | 35 | /** 36 | * Get the port number of an nfl_addr_t address 37 | * @param addr The address to get the port number from 38 | * @return The port number 39 | */ 40 | uint16_t nfl_addr_get_port_network_byte_order(nfl_addr_t *addr); 41 | 42 | #endif //NETFUZZLIB_UTIL_H 43 | -------------------------------------------------------------------------------- /test/udp/udp2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | extern "C" { 14 | #include 15 | #include "module.h" 16 | #include "environment/network_env.h" 17 | } 18 | 19 | class TestUDP2 : public ::testing::Test { 20 | protected: 21 | void SetUp() override { 22 | init_main_library(); 23 | load_config_file("config/udp2.conf"); 24 | } 25 | }; 26 | 27 | TEST_F(TestUDP2, udp4) { 28 | int fd; 29 | struct sockaddr_in6 local_addr, remote_addr; 30 | fd = socket(AF_INET6, SOCK_DGRAM, 0); 31 | ASSERT_TRUE(fd > 0); 32 | memset(&local_addr, 0, sizeof(struct sockaddr_in6)); 33 | memset(&remote_addr, 0, sizeof(struct sockaddr_in6)); 34 | 35 | local_addr.sin6_family = AF_INET6; 36 | local_addr.sin6_port = htons(5000); 37 | 38 | inet_pton(AF_INET6, "::1", &local_addr.sin6_addr); 39 | int res = bind(fd, reinterpret_cast(&local_addr), sizeof(struct sockaddr_in6)); 40 | ASSERT_EQ(res, 0); 41 | 42 | ssize_t n; 43 | socklen_t len = sizeof(struct sockaddr_in6); 44 | char buffer[2200]; 45 | n = recvfrom(fd, buffer, 2200, MSG_WAITALL, (struct sockaddr *)&remote_addr, &len); 46 | 47 | ASSERT_EQ(n, 2050); 48 | uint8_t val_1 = buffer[0]; 49 | uint8_t val_1_expected = '\x85'; 50 | ASSERT_EQ(val_1, val_1_expected); 51 | 52 | ASSERT_TRUE(buffer[sizeof(val_1)] != 0 || buffer[sizeof(val_1) + 1] != 0); 53 | close(fd); 54 | } -------------------------------------------------------------------------------- /src/environment/fd_table.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_FD_TABLE_H 2 | #define NETFUZZLIB_FD_TABLE_H 3 | 4 | #include "sockets/network_types.h" 5 | 6 | /** 7 | * True iff the given file descriptor is a socket file descriptor 8 | * @param fd The file descriptor to check 9 | * @return True iff the given file descriptor is a socket file descriptor 10 | */ 11 | bool is_nfl_sock_fd(int fd); 12 | 13 | /** 14 | * Return the nfl_sock_t for a given file descriptor. 15 | * @param fd The file descriptor to get the nfl_sock_t for 16 | * @return The nfl_sock_t for the given file descriptor, 17 | * or NULL if the file descriptor does not belong to a netfuzzlib socket. 18 | */ 19 | nfl_sock_t *get_nfl_sock(int fd); 20 | 21 | /** 22 | * Allocate space for a new nfl_sock_t and add it to the network environment. 23 | * It is up to the caller to configure all parameters. sock->references is set to 1 24 | * @return the fd of the new allocated socket. 25 | */ 26 | int alloc_nfl_sock(); 27 | 28 | /** 29 | * Free a socket. 30 | * @param sock The socket to free 31 | */ 32 | void free_nfl_sock(nfl_sock_t *sock); 33 | 34 | /** 35 | * Return the next available file descriptor. 36 | * Returns -1 if no file descriptors are available. 37 | */ 38 | int get_available_fd(); 39 | 40 | /** 41 | * Set the given file descriptor to the given socket. 42 | * @param fd The file descriptor to set 43 | * @param sock The socket to set 44 | */ 45 | void fd_table_set(int fd, nfl_sock_t *sock); 46 | 47 | /** 48 | * Clear the given file descriptor from the file descriptor table. 49 | * @param fd The file descriptor to clear 50 | */ 51 | void fd_table_clear(int fd); 52 | 53 | #endif //NETFUZZLIB_FD_TABLE_H 54 | -------------------------------------------------------------------------------- /test/environment/others/others.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" { 4 | #include "netfuzzlib/module_api.h" 5 | #include "module.h" 6 | #include "environment/network_env.h" 7 | #include "environment/interfaces.h" 8 | } 9 | 10 | class TestEnvironmentOthers : public ::testing::Test { 11 | protected: 12 | void SetUp() override { 13 | init_main_library(); 14 | load_config_file("config/network.conf"); 15 | } 16 | }; 17 | 18 | TEST_F(TestEnvironmentOthers, Add_network_device) { 19 | char hw_addr_lo[6] = { 0, 0, 0, 0, 0, 0 }; 20 | unsigned int index; 21 | int err = nfl_add_l2_iface("klee_test", IFF_UP | IFF_LOOPBACK | IFF_RUNNING, 600, hw_addr_lo, hw_addr_lo, &index); 22 | ASSERT_EQ(err, 0); 23 | nfl_l2_iface_t *klee_test = get_l2_iface_by_index(index); 24 | ASSERT_TRUE(klee_test); 25 | ASSERT_STREQ(klee_test->name, "klee_test"); 26 | ASSERT_EQ(if_nametoindex("klee_test"), klee_test->index); 27 | 28 | char test_device_name[IF_NAMESIZE]; 29 | ASSERT_TRUE(if_indextoname(klee_test->index, test_device_name)); 30 | ASSERT_STREQ(test_device_name, "klee_test"); 31 | } 32 | 33 | TEST_F(TestEnvironmentOthers, if_indextoname) { 34 | char index_name[IFNAMSIZ]; 35 | ASSERT_EQ(nullptr, if_indextoname(0, index_name)); 36 | ASSERT_EQ(nullptr, if_indextoname(10, index_name)); 37 | 38 | char *result; 39 | result = if_indextoname(3, index_name); 40 | ASSERT_EQ(nullptr, result); 41 | } 42 | 43 | TEST_F(TestEnvironmentOthers, if_nametoindex) { 44 | unsigned int result = if_nametoindex("lo"); 45 | ASSERT_NE(result, 0); 46 | char index_name[IFNAMSIZ]; 47 | if_indextoname(result, index_name); 48 | ASSERT_STREQ(index_name, "lo"); 49 | } 50 | -------------------------------------------------------------------------------- /cmake/compile_bitcode_library.cmake: -------------------------------------------------------------------------------- 1 | function(prefix_with_path files prefix output_var) 2 | set(_result) 3 | foreach(file ${files}) 4 | list(APPEND _result "${prefix}${file}") 5 | endforeach() 6 | set(${output_var} "${_result}" PARENT_SCOPE) 7 | endfunction(prefix_with_path) 8 | 9 | 10 | function(add_bitcode_library_targets library_name source_files cflags) 11 | # Compile every source file 12 | set(BC_FILES) 13 | foreach(source_file ${source_files}) 14 | # Get filename without extension 15 | get_filename_component(file_name_only "${source_file}" NAME_WE) 16 | set(bc_file "${CMAKE_CURRENT_BINARY_DIR}/${file_name_only}${opt_suffix}.bc" ) 17 | get_filename_component(source_file_type "${source_file}" EXT) 18 | if("${source_file_type}" STREQUAL ".cpp") 19 | add_custom_command( 20 | OUTPUT ${bc_file} 21 | COMMAND ${LLVMCXX} -c "-emit-llvm" ${cflags} "${source_file}" -o ${bc_file} 22 | DEPENDS ${source_file} 23 | ) 24 | else() 25 | add_custom_command( 26 | OUTPUT ${bc_file} 27 | COMMAND ${LLVMCC} -c "-emit-llvm" ${cflags} "${source_file}" -o ${bc_file} 28 | DEPENDS ${source_file} 29 | ) 30 | endif() 31 | 32 | list(APPEND BC_FILES ${bc_file}) 33 | endforeach() 34 | 35 | # Add command to link them to an archive 36 | add_custom_command( 37 | OUTPUT ${CMAKE_BINARY_DIR}/lib${library_name}.bca 38 | COMMAND llvm-ar rcs ${CMAKE_BINARY_DIR}/lib${library_name}.bca ${BC_FILES} 39 | DEPENDS ${BC_FILES} 40 | ) 41 | 42 | add_custom_target(${library_name} DEPENDS "${CMAKE_BINARY_DIR}/lib${library_name}.bca") 43 | endfunction(add_bitcode_library_targets) -------------------------------------------------------------------------------- /src/sockets/stdio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "network_types.h" 4 | #include "hooks/models.h" 5 | 6 | char *fgets_nfl(char *s, int size, nfl_sock_t *sock) { 7 | if (!sock) { 8 | if (size > 0) { 9 | s[0] = '\0'; 10 | } 11 | return NULL; 12 | } 13 | 14 | if (size == 1) { 15 | s[0] = '\0'; 16 | return s; 17 | } 18 | int i; 19 | size_t bytes_read = 0; 20 | bool newline_detected = false; 21 | 22 | for (i = 0; i < (size - 1); i++) { 23 | int c = fgetc_nfl(sock); 24 | if (c == EOF) { 25 | return NULL; 26 | } 27 | s[i] = (char)c; 28 | bytes_read++; 29 | if (c == '\n') { 30 | newline_detected = true; 31 | break; 32 | } 33 | } 34 | s[bytes_read] = '\0'; 35 | if (bytes_read == 0) { 36 | return NULL; 37 | } 38 | if (bytes_read < size - 1 && !newline_detected) { 39 | return NULL; 40 | } 41 | return s; 42 | } 43 | 44 | int fgetc_nfl(nfl_sock_t *sock) { 45 | if (!sock) { 46 | return EOF; 47 | } 48 | unsigned char c; 49 | if (recvfrom_nfl(sock, &c, 1, MSG_DONTWAIT, NULL, 0) == 1) { 50 | return (int)c; 51 | } 52 | return EOF; 53 | } 54 | 55 | size_t fread_nfl(void *ptr, size_t size, size_t nmemb, nfl_sock_t *sock) { 56 | if(!sock) { 57 | return 0; 58 | } 59 | ssize_t ret = recvfrom_nfl(sock, ptr, size * nmemb, MSG_DONTWAIT, NULL, 0); 60 | if( ret < 0) { 61 | return 0; 62 | } 63 | return ret; 64 | } 65 | 66 | size_t fwrite_nfl(const void *ptr, size_t size, size_t nmemb, nfl_sock_t *sock) { 67 | if(!sock) { 68 | return 0; 69 | } 70 | ssize_t ret = sendto_nfl(sock, ptr, size * nmemb, MSG_DONTWAIT, NULL, 0); 71 | if( ret < 0) { 72 | return 0; 73 | } 74 | return ret; 75 | } -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(${CMAKE_VERSION} VERSION_GREATER "3.24") 2 | cmake_policy(SET CMP0135 NEW) 3 | endif() 4 | 5 | include(FetchContent) 6 | FetchContent_Declare(googletest URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip) 7 | # For Windows: Prevent overriding the parent project's compiler/linker settings 8 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 9 | FetchContent_MakeAvailable(googletest) 10 | 11 | enable_testing() 12 | include(GoogleTest) 13 | 14 | add_subdirectory(config) 15 | add_subdirectory(udp/ipv4) 16 | 17 | add_executable(runUnitTests 18 | gtest.cpp 19 | 20 | environment/ioctl/ioctl1.cpp 21 | environment/others/others.cpp 22 | environment/others/dup.cpp 23 | environment/others/stdio.cpp 24 | environment/routing/routing.cpp 25 | 26 | environment/rtnetlink/getaddr/rtnetlink_getaddr_filter.cpp 27 | environment/rtnetlink/getaddr/rtnetlink_getaddr_no_filter.cpp 28 | environment/rtnetlink/getaddr/rtnetlink_getaddr_single_interface.cpp 29 | 30 | environment/rtnetlink/getlink/rtnetlink_getlink_all_devices.cpp 31 | environment/rtnetlink/getlink/rtnetlink_getlink_single_device_filter.cpp 32 | environment/rtnetlink/getlink/rtnetlink_getlink_single_device_no_filter.cpp 33 | environment/rtnetlink/getlink/rtnetlink_getlink_test_helper.cpp 34 | 35 | icmp/ipv6/icmpv6.cpp 36 | 37 | tcp/tcp1.cpp 38 | tcp/tcp-poll.cpp 39 | 40 | udp/udp1.cpp 41 | udp/udp2.cpp 42 | udp/udp_connect.cpp) 43 | 44 | target_link_libraries(runUnitTests gtest gmock 45 | module-config-file-unittest 46 | netfuzzlib) 47 | 48 | add_executable(runUnitTestsPcap 49 | gtest.cpp 50 | module-pcap/pcap.cpp) 51 | 52 | target_link_libraries(runUnitTestsPcap gtest gmock 53 | module-pcap-unittest 54 | netfuzzlib) 55 | 56 | gtest_add_tests(runUnitTests "" AUTO) 57 | gtest_add_tests(runUnitTestsPcap "" AUTO) 58 | gtest_discover_tests(runUnitTests runUnitTestsPcap) -------------------------------------------------------------------------------- /test/udp/ipv4/udp-ipv4-accept.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" { 4 | #include 5 | #include 6 | #include "environment/network_env.h" 7 | } 8 | 9 | class TestUDPv4Accept : public ::testing::Test { 10 | protected: 11 | void SetUp() override { 12 | #ifndef TEST_KERNEL 13 | init_main_library(); 14 | unsigned int device_index = 0; 15 | char mac_eth0[ETHER_ADDR_LEN] = { '\x01', '\x02', '\x03', '\x04', '\x05', '\x06' }; 16 | char mac_eth0_brd[ETHER_ADDR_LEN] = { '\xff', '\xff', '\xff', '\xff', '\xff', '\xff' }; 17 | nfl_add_l2_iface("not-a-real-eth0", IFF_MULTICAST | IFF_UP, 65536, mac_eth0, mac_eth0_brd, &device_index); 18 | nfl_add_l3_iface_ipv4(device_index, "192.168.0.10", "255.255.255.0"); 19 | nfl_set_ipv4_default_gateway("192.168.0.1", device_index); 20 | #endif 21 | } 22 | #ifdef TEST_KERNEL 23 | void TearDown() override { 24 | int socket_type; 25 | socklen_t length; 26 | for (int fd = 0; fd < FD_SETSIZE; fd++) { 27 | socket_type = 0; 28 | length = sizeof(socket_type); 29 | if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &socket_type, &length) == -1) { 30 | continue; 31 | } 32 | if (socket_type != SOCK_DGRAM) 33 | continue; 34 | close(fd); 35 | } 36 | } 37 | #endif 38 | }; 39 | 40 | /* Test if accept on UDP socket is rejected with ENOTSUP. */ 41 | TEST_F(TestUDPv4Accept, accept) { 42 | int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 43 | if (fd < 0) 44 | FAIL() << "socket"; 45 | if (accept(fd, nullptr, nullptr) >= 0) 46 | FAIL() << "accept"; 47 | EXPECT_EQ(errno, ENOTSUP); 48 | } 49 | 50 | /* Test that a socket being non-blocking has no effect on accept failing with 51 | ENOTSUP. */ 52 | TEST_F(TestUDPv4Accept, nonblock) { 53 | int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 54 | if (fd < 0) 55 | FAIL() << "socket"; 56 | if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) 57 | FAIL() << "fcntl"; 58 | if (accept(fd, nullptr, nullptr) >= 0) 59 | FAIL() << "accept"; 60 | EXPECT_EQ(errno, ENOTSUP); 61 | } -------------------------------------------------------------------------------- /src/environment/network_env.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "network_env.h" 5 | #include "import_host.h" 6 | #include "hooks/hooks.h" 7 | #include "interfaces.h" 8 | 9 | int init_main_library() { 10 | char *env_enable_import_host_network_devices = getenv("ENABLE_IMPORT_HOST_NETWORK_DEVICES"); 11 | 12 | bool enable_import_host_network_devices = env_enable_import_host_network_devices && strcmp(env_enable_import_host_network_devices, "0") != 0; 13 | bool autogen_loopback_device = !getenv("DISABLE_LOOPBACK_DEVICE_AUTOGEN"); 14 | bool autogen_ipv6_link_local = !getenv("DISABLE_IPV6_LINK_LOCAL_AUTOGEN"); 15 | 16 | nfl_log_info("Network environment configuration:, ENABLE_IMPORT_HOST_NETWORK_DEVICES: %d, DISABLE_LOOPBACK_DEVICE_AUTOGEN: %d," 17 | "DISABLE_IPV6_LINK_LOCAL_AUTOGEN: %d", 18 | enable_import_host_network_devices, !autogen_loopback_device, !autogen_ipv6_link_local); 19 | network_env *env = get_network_env(); 20 | memset(env, 0, sizeof(network_env)); 21 | nfl_set_free_pkts(true); 22 | 23 | if (autogen_loopback_device) { 24 | if (enable_import_host_network_devices) { 25 | nfl_log_info("Skipping automatic adding lo device since importing host network l2_interfaces is enabled."); 26 | } else { 27 | add_loopback_device(); 28 | } 29 | } 30 | if (enable_import_host_network_devices) { 31 | import_host_network_devices(); 32 | } 33 | 34 | liveness_ctr_clear(); 35 | int fd_dev_null = open("/dev/null", O_RDONLY); 36 | if (fd_dev_null < 0) { 37 | nfl_log_error("Could not open /dev/null"); 38 | return -1; 39 | } 40 | env->fd_dev_null = dup2_native(fd_dev_null, NFL_FD_DEV_NULL); 41 | close_native(fd_dev_null); 42 | if (env->fd_dev_null < 0) { 43 | nfl_log_error("Could not dup2 /dev/null"); 44 | return -1; 45 | } 46 | return 0; 47 | } 48 | 49 | void nfl_set_free_pkts(bool free_enabled) { 50 | get_network_env()->enable_packet_free = free_enabled; 51 | } 52 | 53 | inline network_env *get_network_env() { 54 | static network_env network_env = { 0 }; 55 | return &network_env; 56 | } 57 | -------------------------------------------------------------------------------- /test/environment/others/dup.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" { 5 | #include "../../../include/netfuzzlib/module_api.h" 6 | #include "module.h" 7 | #include "../../../src/environment/network_env.h" 8 | } 9 | 10 | class TestEnvironmentDup : public ::testing::Test { 11 | protected: 12 | int sockfd; 13 | 14 | void SetUp() override { 15 | init_main_library(); 16 | load_config_file("config/tcp1.conf"); 17 | 18 | struct sockaddr_in remote_addr {}; 19 | 20 | sockfd = socket(AF_INET, SOCK_STREAM, 0); 21 | remote_addr.sin_family = AF_INET; 22 | inet_aton("127.0.0.5", &remote_addr.sin_addr); 23 | remote_addr.sin_port = htons(5000); 24 | connect(sockfd, reinterpret_cast(&remote_addr), sizeof(remote_addr)); 25 | } 26 | }; 27 | 28 | TEST_F(TestEnvironmentDup, testDup) { 29 | char buf[10]{}; 30 | 31 | ssize_t ret = read(sockfd, buf, 1); 32 | ASSERT_EQ(ret, 1); 33 | ASSERT_EQ(buf[0], 0x06); 34 | int dupfd = dup(sockfd); 35 | ASSERT_GT(dupfd, 0); 36 | 37 | ret = read(dupfd, buf, 1); 38 | ASSERT_EQ(ret, 1); 39 | ASSERT_EQ(buf[0], 0x10); 40 | 41 | ret = read(sockfd, buf, 1); 42 | ASSERT_EQ(ret, 1); 43 | ASSERT_EQ(buf[0], '\xAA'); 44 | } 45 | 46 | TEST_F(TestEnvironmentDup, testDup2) { 47 | char buf[10]{}; 48 | int dupfd = 200; 49 | 50 | ssize_t ret = read(sockfd, buf, 1); 51 | ASSERT_EQ(ret, 1); 52 | ASSERT_EQ(buf[0], 0x06); 53 | int result = dup2(sockfd, dupfd); 54 | ASSERT_EQ(result, dupfd); 55 | 56 | ret = read(dupfd, buf, 1); 57 | ASSERT_EQ(ret, 1); 58 | ASSERT_EQ(buf[0], 0x10); 59 | 60 | ret = read(sockfd, buf, 1); 61 | ASSERT_EQ(ret, 1); 62 | ASSERT_EQ(buf[0], '\xAA'); 63 | } 64 | 65 | TEST_F(TestEnvironmentDup, testDup3) { 66 | char buf[10]{}; 67 | int dupfd = 200; 68 | 69 | ssize_t ret = read(sockfd, buf, 1); 70 | ASSERT_EQ(ret, 1); 71 | ASSERT_EQ(buf[0], 0x06); 72 | int result = dup3(sockfd, dupfd, 0); 73 | ASSERT_EQ(result, dupfd); 74 | 75 | ret = read(dupfd, buf, 1); 76 | ASSERT_EQ(ret, 1); 77 | ASSERT_EQ(buf[0], 0x10); 78 | 79 | ret = read(sockfd, buf, 1); 80 | ASSERT_EQ(ret, 1); 81 | ASSERT_EQ(buf[0], '\xAA'); 82 | } 83 | -------------------------------------------------------------------------------- /src/environment/util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "netfuzzlib/api.h" 6 | #include "netfuzzlib/util.h" 7 | 8 | socklen_t get_socket_domain_addrlen(int domain) { 9 | switch (domain) { 10 | case (AF_INET): 11 | return sizeof(struct sockaddr_in); 12 | case (AF_INET6): 13 | return sizeof(struct sockaddr_in6); 14 | case (AF_NETLINK): 15 | return sizeof(struct sockaddr_nl); 16 | default: 17 | nfl_exit_log(1, "get_socket_domain_addrlen on invalid socket domain"); 18 | } 19 | } 20 | 21 | bool addr_is_zero_address(const nfl_addr_t *addr) { 22 | switch (addr->s.sa_family) { 23 | case (AF_INET): 24 | return addr->s4.sin_addr.s_addr == INADDR_ANY; 25 | case (AF_INET6): 26 | return IN6_IS_ADDR_UNSPECIFIED(&addr->s6.sin6_addr); 27 | } 28 | __builtin_unreachable(); 29 | } 30 | 31 | bool ip_endpoints_match(const nfl_addr_t *addr1, const nfl_addr_t *addr2) { 32 | if (addr1->s.sa_family != addr2->s.sa_family) 33 | return false; 34 | bool match_by_wildcard_address = addr_is_zero_address(addr1) || addr_is_zero_address(addr2); 35 | switch (addr1->s.sa_family) { 36 | case (AF_INET): { 37 | if (addr1->s4.sin_port != addr2->s4.sin_port && addr1->s4.sin_port != 0 && addr2->s4.sin_port != 0) 38 | return false; 39 | return match_by_wildcard_address || (addr1->s4.sin_addr.s_addr == addr2->s4.sin_addr.s_addr); 40 | } 41 | case (AF_INET6): { 42 | if (addr1->s6.sin6_port != addr2->s6.sin6_port && addr1->s6.sin6_port != 0 && addr2->s6.sin6_port != 0) 43 | return false; 44 | return match_by_wildcard_address || (memcmp(&addr1->s6.sin6_addr, &addr2->s6.sin6_addr, sizeof(struct in6_addr)) == 0); 45 | } 46 | } 47 | __builtin_unreachable(); 48 | } 49 | 50 | ssize_t iov_count_bytes(struct iovec *iov, size_t iovlen) { 51 | ssize_t total = 0; 52 | for (size_t i = 0; i < iovlen; i++) { 53 | total += (ssize_t)iov[i].iov_len; 54 | } 55 | return total; 56 | } 57 | 58 | uint16_t nfl_addr_get_port_network_byte_order(nfl_addr_t *addr) { 59 | switch (addr->s.sa_family) { 60 | case (AF_INET): 61 | return addr->s4.sin_port; 62 | case (AF_INET6): 63 | return addr->s6.sin6_port; 64 | } 65 | __builtin_unreachable(); 66 | } -------------------------------------------------------------------------------- /src/environment/interfaces.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_INTERFACES_H 2 | #define NETFUZZLIB_INTERFACES_H 3 | 4 | #include "sockets/network_types.h" 5 | /** 6 | * Return the nfl_l2_iface_t corresponding to a given interface index (e.g. 1 or 2) 7 | * Returns NULL if no such device exists. 8 | * @param index The index of the device to get 9 | * @return The nfl_l2_iface_t corresponding to the given device index 10 | */ 11 | nfl_l2_iface_t *get_l2_iface_by_index(unsigned int index); 12 | 13 | /** 14 | * Return the nfl_l2_iface_t corresponding to a given interface name (e.g. eth0 or lo) 15 | * Returns NULL if no such device exists. 16 | * @param name The name of the device to get 17 | * @return The nfl_l2_iface_t corresponding to the given device name 18 | */ 19 | nfl_l2_iface_t *get_l2_iface_by_name(const char *name); 20 | 21 | /** 22 | * Add an nfl_l3_iface_t to an nfl_l2_iface_t. 23 | * @param l2_iface The nfl_l2_iface_t to add l3_iface to 24 | * @param l3_iface The nfl_l3_iface_t to add 25 | */ 26 | void add_l3_iface_to_l2_iface(nfl_l2_iface_t *l2_iface, nfl_l3_iface_t *l3_iface); 27 | 28 | /** 29 | * Return whether a given address is eligible for binding 30 | * to a given sock, e.g. it is the address of an existing interface (in the nfl_l3_iface_t list), 31 | * is a broadcast or multicast address for a network we're on, applicable for the given sock 32 | * or is a special address like 0.0.0.0 or ::0, (INADDR_ANY). 33 | */ 34 | bool can_bind_to_address(nfl_sock_t *sock, const nfl_addr_t *addr); 35 | 36 | /** 37 | * Get the ipv4 local broadcast address of an ipv4 nfl_l3_iface_t 38 | * @param l3_iface The ipv4 nfl_l3_iface_t to get the broadcast address for 39 | * @param broadcast The sockaddr_in to write the broadcast address to 40 | */ 41 | void get_l3_iface_broadcast_addr(const nfl_l3_iface_t *l3_iface, struct sockaddr_in *broadcast); 42 | 43 | /** 44 | * Return the amount of L3 ipv4 interfaces 45 | * @return The amount of L3 ipv4 interfaces 46 | */ 47 | int get_l3_iface_ipv4_count(); 48 | 49 | /** 50 | * Return whether a given l2_iface is the loopback interface 51 | * @param l2_iface The l2_iface to check 52 | * @return True iff the given l2_iface is the loopback interface 53 | */ 54 | bool l2_iface_is_loopback(nfl_l2_iface_t *l2_iface); 55 | 56 | /** 57 | * Add a loopback device (127.0.0.1 / ::1) 58 | */ 59 | int add_loopback_device(); 60 | 61 | #endif //NETFUZZLIB_INTERFACES_H 62 | -------------------------------------------------------------------------------- /test/tcp/tcp-poll.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" { 4 | #include 5 | 6 | #include 7 | #include 8 | #include "../../src/environment/network_env.h" 9 | #include "module.h" 10 | } 11 | 12 | class TestTCPPoll : public ::testing::Test { 13 | protected: 14 | void SetUp() override { 15 | init_main_library(); 16 | load_config_file("config/tcp2.conf"); 17 | } 18 | }; 19 | ; 20 | 21 | TEST_F(TestTCPPoll, test_pollNoConns) { 22 | int fd = socket(AF_INET, SOCK_STREAM, 0); 23 | ASSERT_NE(fd, -1); 24 | 25 | struct sockaddr_in addr; 26 | addr.sin_family = AF_INET; 27 | addr.sin_port = htons(9999); 28 | addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 29 | 30 | int ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); 31 | ASSERT_EQ(ret, 0); 32 | 33 | listen(fd, 100); 34 | struct pollfd fds[1]; 35 | fds[0].fd = fd; 36 | fds[0].events = POLLIN; 37 | 38 | ret = poll(fds, 1, 0); 39 | ASSERT_EQ(ret, 0); 40 | ASSERT_FALSE(fds[0].revents & POLLIN); 41 | 42 | ret = close(fd); 43 | ASSERT_EQ(ret, 0); 44 | } 45 | 46 | TEST_F(TestTCPPoll, test_poll) { 47 | int fd = socket(AF_INET, SOCK_STREAM, 0); 48 | ASSERT_NE(fd, -1); 49 | 50 | struct sockaddr_in addr; 51 | addr.sin_family = AF_INET; 52 | addr.sin_port = htons(2000); 53 | addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 54 | 55 | int ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); 56 | ASSERT_EQ(ret, 0); 57 | 58 | struct pollfd fds[1]; 59 | fds[0].fd = fd; 60 | fds[0].events = POLLIN; 61 | fds[0].revents = 0; 62 | 63 | ret = poll(fds, 1, 0); 64 | ASSERT_EQ(ret, 0); 65 | ASSERT_FALSE(fds[0].revents & POLLIN); 66 | 67 | listen(fd, 100); 68 | fds[0].fd = fd; 69 | fds[0].events = POLLIN; 70 | fds[0].revents = 0; 71 | 72 | ret = poll(fds, 1, 0); 73 | ASSERT_EQ(ret, 1); 74 | ASSERT_TRUE(fds[0].revents & POLLIN); 75 | 76 | accept(fd, NULL, NULL); 77 | 78 | fds[0].fd = fd; 79 | fds[0].events = POLLIN; 80 | fds[0].revents = 0; 81 | ret = poll(fds, 1, 0); 82 | ASSERT_EQ(ret, 1); 83 | ASSERT_TRUE(fds[0].revents & POLLIN); 84 | 85 | accept(fd, NULL, NULL); 86 | 87 | fds[0].fd = fd; 88 | fds[0].events = POLLIN; 89 | 90 | ret = poll(fds, 1, 0); 91 | ASSERT_EQ(ret, 0); 92 | ASSERT_FALSE(fds[0].revents & POLLIN); 93 | 94 | ret = close(fd); 95 | ASSERT_EQ(ret, 0); 96 | } -------------------------------------------------------------------------------- /cmake/find_bitcode_compiler.cmake: -------------------------------------------------------------------------------- 1 | #===------------------------------------------------------------------------===# 2 | # 3 | # The KLEE Symbolic Virtual Machine 4 | # 5 | # This file is distributed under the University of Illinois Open Source 6 | # License. See LICENSE.TXT for details. 7 | # 8 | #===------------------------------------------------------------------------===# 9 | # 10 | # This file tries to find compilers to build LLVM bitcode. 11 | # It is implicitly dependent on `find_llvm.cmake` already being run in the 12 | # same scope. 13 | # 14 | #===------------------------------------------------------------------------===# 15 | 16 | message(STATUS "Looking for bitcode compilers") 17 | 18 | find_program( 19 | LLVMCC 20 | NAMES "clang-${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}" "clang" "llvm-gcc" 21 | # Give the LLVM tools directory higher priority than the system directory. 22 | HINTS "${LLVM_TOOLS_BINARY_DIR}" 23 | ) 24 | if (LLVMCC) 25 | message(STATUS "Found ${LLVMCC}") 26 | else() 27 | message(FATAL_ERROR "Failed to find C bitcode compiler") 28 | endif() 29 | 30 | find_program( 31 | LLVMCXX 32 | NAMES "clang++-${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}" "clang++" "llvm-g++" 33 | # Give the LLVM tools directory higher priority than the system directory. 34 | HINTS "${LLVM_TOOLS_BINARY_DIR}" 35 | ) 36 | if (LLVMCXX) 37 | message(STATUS "Found ${LLVMCXX}") 38 | else() 39 | message(FATAL_ERROR "Failed to find C++ bitcode compiler") 40 | endif() 41 | 42 | # Test compiler 43 | function(test_bitcode_compiler COMPILER SRC_EXT) 44 | message(STATUS "Testing bitcode compiler ${COMPILER}") 45 | set(SRC_FILE "${CMAKE_BINARY_DIR}/test_bitcode_compiler.${SRC_EXT}") 46 | file(WRITE "${SRC_FILE}" "int main(int argc, char** argv) { return 0;}") 47 | set(BC_FILE "${SRC_FILE}.bc") 48 | execute_process( 49 | COMMAND 50 | "${COMPILER}" 51 | "-c" 52 | "-emit-llvm" 53 | "-o" "${BC_FILE}" 54 | "${SRC_FILE}" 55 | RESULT_VARIABLE COMPILE_INVOKE_EXIT_CODE 56 | ) 57 | if ("${COMPILE_INVOKE_EXIT_CODE}" EQUAL 0) 58 | message(STATUS "Compile success") 59 | else() 60 | message(FATAL_ERROR "Compilation failed") 61 | endif() 62 | 63 | # Remove temporary files. It's okay to not remove these on failure 64 | # as they will be useful for developer debugging. 65 | file(REMOVE "${SRC_FILE}") 66 | file(REMOVE "${BC_FILE}") 67 | endfunction() 68 | 69 | test_bitcode_compiler("${LLVMCC}" "c") 70 | test_bitcode_compiler("${LLVMCXX}" "cxx") 71 | -------------------------------------------------------------------------------- /test/environment/rtnetlink/getlink/rtnetlink_getlink_test_helper.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "rtnetlink_getlink_test_helper.h" 6 | 7 | void test_link(const struct nlmsghdr *msg, const char *name, const char *hw_addr, const char *hw_broadcast_addr, int mtu, unsigned int flags) { 8 | struct ifinfomsg *ifinfo; 9 | struct rtattr *attr; 10 | unsigned long len; 11 | 12 | ifinfo = (struct ifinfomsg *)NLMSG_DATA(msg); 13 | ASSERT_EQ(ifinfo->ifi_flags, flags); 14 | len = msg->nlmsg_len - NLMSG_ALIGN(sizeof(struct ifinfomsg) + NLMSG_ALIGN(sizeof(struct nlmsghdr))); 15 | int attr_count = 0; 16 | 17 | bool ifla_address_seen = false, ifla_broadcast_seen = false, ifla_name_seen = false, ifla_mtu_seen = false, ifla_qdisc_seen = false, 18 | ifla_stats_seen = false; 19 | 20 | for (attr = IFLA_RTA(ifinfo); RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) { 21 | attr_count++; 22 | switch (attr->rta_type) { 23 | case IFLA_ADDRESS: 24 | ifla_address_seen = true; 25 | ASSERT_EQ(memcmp(hw_addr, RTA_DATA(attr), ETHER_ADDR_LEN), 0); 26 | break; 27 | case IFLA_BROADCAST: { 28 | ifla_broadcast_seen = true; 29 | ASSERT_EQ(memcmp(hw_broadcast_addr, RTA_DATA(attr), ETHER_ADDR_LEN), 0); 30 | break; 31 | } 32 | case IFLA_IFNAME: { 33 | ifla_name_seen = true; 34 | ASSERT_STREQ((char *)RTA_DATA(attr), name); 35 | break; 36 | } 37 | case IFLA_MTU: { 38 | ifla_mtu_seen = true; 39 | assert(*(int *)RTA_DATA(attr) == mtu); 40 | break; 41 | } 42 | case IFLA_QDISC: { 43 | ifla_qdisc_seen = true; 44 | ASSERT_STREQ((char *)RTA_DATA(attr), "noqueue"); 45 | break; 46 | } 47 | case IFLA_STATS: { 48 | ifla_stats_seen = true; 49 | struct rtnl_link_stats *stats = (struct rtnl_link_stats *)RTA_DATA(attr); 50 | char *buf = (char *)stats; 51 | int i; 52 | for (i = 0; i < sizeof(struct rtnl_link_stats); i++) { 53 | ASSERT_EQ(buf[i], 0); 54 | } 55 | break; 56 | } 57 | default: 58 | FAIL(); //"Unknown flags!" 59 | } 60 | } 61 | ASSERT_TRUE(ifla_address_seen); 62 | ASSERT_TRUE(ifla_broadcast_seen); 63 | ASSERT_TRUE(ifla_name_seen); 64 | ASSERT_TRUE(ifla_mtu_seen); 65 | ASSERT_TRUE(ifla_qdisc_seen); 66 | ASSERT_TRUE(ifla_stats_seen); 67 | ASSERT_EQ(attr_count, 6); 68 | } -------------------------------------------------------------------------------- /src/hooks/hooks.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_HOOKS_H 2 | #define NETFUZZLIB_HOOKS_H 3 | 4 | #include "models.h" 5 | #include "native.h" 6 | #include "environment/fd_table.h" 7 | #include 8 | #include 9 | 10 | #define SWITCH_MODEL_NATIVE(fd, userspace_func, native_func, args...) \ 11 | do { \ 12 | nfl_sock_t *sock = get_nfl_sock(fd); \ 13 | if (sock) { \ 14 | errno = 0; \ 15 | return userspace_func(sock, args); \ 16 | } else { \ 17 | nfl_log_debug("Forwarding %s() to %s", __func__, native_fd_to_str(fd)); \ 18 | return native_func(fd, args); \ 19 | } \ 20 | } while (0) 21 | 22 | #define SWITCH_MODEL_NATIVE_STREAM(stream, userspace_func, native_func, args...) \ 23 | do { \ 24 | int fd = fileno(stream); \ 25 | if (stream_is_casted_fd(stream) || is_nfl_sock_fd((fd))) { \ 26 | errno = 0; \ 27 | nfl_sock_t *sock = get_nfl_sock(fd); \ 28 | return userspace_func(args, sock); \ 29 | } else { \ 30 | return native_func(args, stream); \ 31 | } \ 32 | } while (0) 33 | 34 | #ifndef CLOSE_RANGE_CLOEXEC 35 | #define CLOSE_RANGE_CLOEXEC (1U << 2) 36 | #endif 37 | 38 | void liveness_ctr_clear(); 39 | void nfl_end_priv(); 40 | char *native_fd_to_str(int fd); 41 | 42 | bool stream_is_casted_fd(FILE *stream); 43 | 44 | /** 45 | * Return whether a combination of domain, type and protocol is supported by netfuzzlib. 46 | * @param domain The domain to check, e.g., AF_INET 47 | * @param type The socket type to check, e.g., SOCK_STREAM 48 | * @param protocol The socket protocol to check, e.g., IPPROTO_TCP 49 | * @return True iff the given combination of domain, type and protocol is supported by netfuzzlib. 50 | */ 51 | bool is_socket_supported(int domain, int type, int protocol); 52 | 53 | #endif // NETFUZZLIB_HOOKS_H 54 | -------------------------------------------------------------------------------- /src/environment/fd_table.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "fd_table.h" 4 | #include "netfuzzlib/api.h" 5 | #include "sockets/network_types.h" 6 | #include "network_env.h" 7 | #include "sockets/sockets_util.h" 8 | 9 | void fd_table_set(int fd, nfl_sock_t *sock) { 10 | if (get_network_env()->fd_table[fd] != sock) { 11 | sock->references++; 12 | get_network_env()->fd_table[fd] = sock; 13 | } 14 | } 15 | 16 | void fd_table_clear(int fd) { 17 | get_network_env()->fd_table[fd] = NULL; 18 | } 19 | 20 | void free_nfl_sock(nfl_sock_t *sock) { 21 | if (sock->local_addr) { 22 | free(sock->local_addr); 23 | } 24 | 25 | if (sock->remote_addr) { 26 | free(sock->remote_addr); 27 | } 28 | 29 | if (sock->packets_ll) { 30 | free_packet_ll(sock->packets_ll); 31 | } 32 | free(sock); 33 | } 34 | 35 | int get_available_fd() { 36 | for (int i = SOCKET_FD_START; i < SOCKET_FD_MAX; i++) { 37 | if (!get_network_env()->fd_table[i]) 38 | return i; 39 | } 40 | return -1; 41 | } 42 | 43 | int alloc_nfl_sock() { 44 | int fd = get_available_fd(); 45 | if (fd < 0) 46 | return -1; 47 | nfl_sock_t *sock = calloc(1, sizeof(nfl_sock_t)); 48 | if (!sock) 49 | return -1; 50 | fd_table_set(fd, sock); 51 | sock->references = 1; 52 | return fd; 53 | } 54 | 55 | bool is_nfl_sock_fd(int fd) { 56 | return get_nfl_sock(fd) != NULL; 57 | } 58 | 59 | nfl_sock_t *get_nfl_sock(int fd) { 60 | if (fd < 0 || fd > SOCKET_FD_MAX) { 61 | return NULL; 62 | } 63 | return get_network_env()->fd_table[fd]; 64 | } 65 | 66 | int close_nfl_sock(nfl_sock_t *sock) { 67 | nfl_log_debug("close() for %s", sock_to_str(sock)); 68 | for (int i = 0; i < SOCKET_FD_MAX; i++) { 69 | if (get_nfl_sock(i) == sock) { 70 | fd_table_clear(i); 71 | } 72 | } 73 | free_nfl_sock(sock); 74 | return 0; 75 | } 76 | 77 | int close_nfl_fd(int fd) { 78 | nfl_sock_t *sock = get_nfl_sock(fd); 79 | if (!sock) { 80 | errno = EINVAL; 81 | return -1; 82 | } 83 | nfl_log_debug("close() for %s", sock_to_str(sock)); 84 | sock->references--; 85 | if (sock->references <= 0) { 86 | free_nfl_sock(sock); 87 | } 88 | fd_table_clear(fd); 89 | return 0; 90 | } 91 | 92 | int close_range_nfl(unsigned int low_fd, unsigned int max_fd, int flags) { 93 | for (int i = (int)low_fd; i < max_fd && i < SOCKET_FD_MAX; i++) { 94 | nfl_sock_t *sock = get_nfl_sock(i); 95 | if (sock) { 96 | sock->references--; 97 | if (sock->references <= 0) { 98 | free_nfl_sock(sock); 99 | } 100 | fd_table_clear(i); 101 | } 102 | } 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /src/hooks/models.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_MODELS_H 2 | #define NETFUZZLIB_MODELS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "sockets/network_types.h" 10 | 11 | int socket_nfl(int domain, int type, int protocol); 12 | int bind_nfl(nfl_sock_t *sock, const nfl_addr_t *addr, socklen_t len); 13 | int connect_nfl(nfl_sock_t *sock, const nfl_addr_t *addr, socklen_t addrlen); 14 | int accept_nfl(nfl_sock_t *sock, nfl_addr_t *addr, socklen_t *len); 15 | int accept4_nfl(nfl_sock_t *sock, nfl_addr_t *addr, socklen_t *len, int flags); 16 | int getpeername_nfl(nfl_sock_t *sock, nfl_addr_t *address, socklen_t *addrlen); 17 | int getsockname_nfl(nfl_sock_t *sock, nfl_addr_t *address, socklen_t *addrlen); 18 | int getsockopt_nfl(nfl_sock_t *sock, int level, int option_name, void *option_value, socklen_t *option_len); 19 | int setsockopt_nfl(nfl_sock_t *sock, int level, int option_name, const void *option_value, socklen_t option_len); 20 | int listen_nfl(nfl_sock_t *sock, int backlog); 21 | 22 | int close_nfl_fd(int fd); 23 | int close_nfl_sock(nfl_sock_t *sock); 24 | 25 | int shutdown_nfl(nfl_sock_t *sock, int how); 26 | int select_nfl(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds); 27 | int poll_nfl(struct pollfd *fds, nfds_t nfds, int timeout); 28 | 29 | int ioctl_nfl(nfl_sock_t *sock, unsigned long request, void *argp); 30 | int vioctl_nfl(nfl_sock_t *sock, unsigned long request, va_list argp); 31 | int pipe_nfl(int filedes[2]); 32 | ssize_t read_nfl(nfl_sock_t *sock, void *buf, size_t count); 33 | ssize_t recvfrom_nfl(nfl_sock_t *sock, void *buf, size_t len, int flags, nfl_addr_t *remote_addr, socklen_t *addrlen); 34 | ssize_t recvmsg_nfl(nfl_sock_t *sock, struct msghdr *msg, int flags); 35 | int recvmmsg_nfl(nfl_sock_t *sock, void *msgvec, unsigned int vlen, int flags, struct timespec *timeout); 36 | ssize_t write_nfl(nfl_sock_t *sock, void const *buf, size_t len); 37 | ssize_t sendto_nfl(nfl_sock_t *sock, const void *buf, size_t len, int flags, const nfl_addr_t *remote_addr, socklen_t addrlen); 38 | ssize_t sendmsg_nfl(nfl_sock_t *sock, const struct msghdr *msg, int flags); 39 | 40 | int fcntl_nfl(nfl_sock_t *sock, int cmd, ...); 41 | unsigned int if_nametoindex_nfl(const char *name); 42 | char *if_indextoname_nfl(unsigned int index, char *ifname); 43 | 44 | int getifaddrs_nfl(struct ifaddrs **ifap); 45 | void freeifaddrs_nfl(struct ifaddrs *ifa); 46 | 47 | int dup_nfl_sock(nfl_sock_t *old_sock); 48 | int dup_nfl_fd(int oldfd); 49 | int dup2_nfl(int oldfd, int newfd); 50 | int dup3_nfl(int oldfd, int newfd, int flags); 51 | 52 | size_t fread_nfl(void *ptr, size_t size, size_t nmemb, nfl_sock_t *sock); 53 | size_t fwrite_nfl(const void *ptr, size_t size, size_t nmemb, nfl_sock_t *sock); 54 | char *fgets_nfl(char *s, int size, nfl_sock_t *sock); 55 | int fgetc_nfl(nfl_sock_t *sock); 56 | 57 | int close_range_nfl(unsigned int low_fd, unsigned int max_fd, int flags); 58 | 59 | #endif //NETFUZZLIB_MODELS_H 60 | -------------------------------------------------------------------------------- /include/netfuzzlib/module_api.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_MODULE_API_H 2 | #define NETFUZZLIB_MODULE_API_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /** 9 | * Initialize this module, called once during environment setup. 10 | * Usually adding network interfaces happens here. 11 | */ 12 | int nfl_initialize(); 13 | 14 | /** 15 | * Define whether an attempted outgoing tcp connection should succeed 16 | * Parameters local_addr and remote_addr are guaranteed to be of the same type, sockaddr_in or sockaddr_in6 17 | * @param local_addr The local address of the sock in case the connect would be successful. 18 | * @param remote_addr The remote address of the attempted connection. 19 | * @return True on successful connection, false otherwise. 20 | */ 21 | bool nfl_tcp_connect(const nfl_sock_module_t *sock, const nfl_addr_t *local_addr, const nfl_addr_t *remote_addr); 22 | 23 | /** 24 | * Define an incoming tcp connection. Called when an application invokes 'accept' on a listening sock. 25 | * Parameters local_addr and remote_addr are guaranteed to be of same type, sockaddr_in or sockaddr_in6 26 | * @param local_addr The local address bound to the sock. 27 | * @param remote_addr The address of the remote endpoint. This must be initialized by the module in case the connection was successful. 28 | * @return True on successful connection, false otherwise. 29 | */ 30 | bool nfl_tcp_accept(const nfl_sock_module_t *sock, const nfl_addr_t *local_addr, nfl_addr_t *remote_addr); 31 | 32 | /** 33 | * Called when an application attempts to send data on a network sock 34 | * @param sock The sock on which a send call was issued 35 | * @param from The sender address of the packet, type sockaddr_in | sockaddr_in6 36 | * @param to The destination address of the packet, type sockaddr_in | sockaddr_in6 37 | * @param iov Array of iovec structs containing the outgoing data 38 | * @param iovlen The amount of iovec structs in the array 39 | * @return The amount of bytes sent, or a negative value in case of an error 40 | */ 41 | ssize_t nfl_send(const nfl_sock_module_t *sock, const nfl_addr_t *from, const nfl_addr_t *to, struct iovec *iov, size_t iovlen); 42 | 43 | /** 44 | * Called when an application attempts to read data on a network sock, and the current buffer is empty 45 | * @param sock The sock on which a read call was issued 46 | * @param bound_addr The address bound to the sock, type sockaddr_in | sockaddr_in6 47 | * @return Packet which must be allocated and initialized by the network environment, see nfl_alloc_pkt() in module_provided.h 48 | * Must remain unaltered if no packet has been received. 49 | * For TCP only the iov field needs to be filled in, other fields are ignored. 50 | */ 51 | nfl_pkt *nfl_receive(const nfl_sock_module_t *sock, const nfl_addr_t *bound_addr); 52 | 53 | void nfl_end(); 54 | 55 | //Reasons for dying: blocking, or liveness heuristic. 56 | 57 | // Liveness heuristic: actions: ignore or die 58 | // Blocking: actions: block or die. 59 | 60 | #endif //NETFUZZLIB_MODULE_API_H 61 | -------------------------------------------------------------------------------- /src/hooks/native.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_NATIVE_H 2 | #define NETFUZZLIB_NATIVE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int socket_native(int domain, int type, int protocol); 11 | int bind_native(int fd, const struct sockaddr *addr, socklen_t len); 12 | int connect_native(int fd, const struct sockaddr *addr, socklen_t addrlen); 13 | int accept_native(int fd, struct sockaddr *addr, socklen_t *len); 14 | int accept4_native(int fd, struct sockaddr *addr, socklen_t *len, int flags); 15 | int getpeername_native(int fd, struct sockaddr *address, socklen_t *addrlen); 16 | int getsockname_native(int fd, struct sockaddr *address, socklen_t *addrlen); 17 | int getsockopt_native(int fd, int level, int option_name, void *option_value, socklen_t *option_len); 18 | int setsockopt_native(int fd, int level, int option_name, const void *option_value, socklen_t option_len); 19 | int listen_native(int fd, int backlog); 20 | int close_native(int fd); 21 | int shutdown_native(int fd, int how); 22 | int fcntl_native(int fd, int cmd, ...); 23 | int fcntl64_native(int fd, int cmd, ...); 24 | 25 | int select_native(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 26 | int pselect_native(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask); 27 | 28 | int poll_native(struct pollfd *fds, nfds_t nfds, int timeout); 29 | int ppoll_native(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask); 30 | 31 | int ioctl_native(int fd, unsigned long request, void *argp); 32 | 33 | int pipe_native(int filedes[2]); 34 | 35 | ssize_t read_native(int fd, void *buf, size_t count); 36 | ssize_t recvfrom_native(int fd, void *buf, size_t len, int flags, struct sockaddr *remote_addr, socklen_t *addrlen); 37 | ssize_t recvmsg_native(int fd, struct msghdr *msg, int flags); 38 | int recvmmsg_native(int fd, void *msgvec, unsigned int vlen, int flags, struct timespec *timeout); 39 | 40 | ssize_t write_native(int fd, void const *buf, size_t len); 41 | ssize_t sendto_native(int fd, const void *buf, size_t len, int flags, const struct sockaddr *remote_addr, socklen_t addrlen); 42 | ssize_t sendmsg_native(int fd, const struct msghdr *msg, int flags); 43 | 44 | int dup_native(int oldfd); 45 | int dup2_native(int oldfd, int newfd); 46 | int dup3_native(int oldfd, int newfd, int flags); 47 | 48 | int fileno_native(FILE *stream); 49 | FILE *fdopen_native(int fd, const char *mode); 50 | char *fgets_native(char *s, int size, FILE *stream); 51 | int fgetc_native(FILE *stream); 52 | size_t fread_native(void *ptr, size_t size, size_t nmemb, FILE *stream); 53 | size_t fwrite_native(const void *ptr, size_t size, size_t nmemb, FILE *stream); 54 | int fclose_native(FILE *stream); 55 | int fflush_native(FILE *stream); 56 | int vfprintf_native(FILE *stream, const char *format, va_list args); 57 | 58 | void closefrom_native(int low_fd); 59 | int close_range_native(unsigned int low_fd, unsigned int max_fd, unsigned int flags); 60 | 61 | #endif //NETFUZZLIB_NATIVE_H 62 | -------------------------------------------------------------------------------- /src/hooks/hooks-stdio.c: -------------------------------------------------------------------------------- 1 | #include "hooks.h" 2 | #include "environment/fd_table.h" 3 | 4 | bool stream_is_casted_fd(FILE *stream) { 5 | long fd = (long)stream; 6 | return fd > 0 && fd < SOCKET_FD_MAX; 7 | } 8 | 9 | int fileno(FILE *stream) { 10 | if (stream_is_casted_fd(stream)) { 11 | return (int)(long)stream; 12 | } 13 | return fileno_native(stream); 14 | } 15 | 16 | FILE *fdopen(int fd, const char *mode) { 17 | if (is_nfl_sock_fd(fd)) { 18 | return (FILE *)(long)fd; 19 | } 20 | return fdopen_native(fd, mode); 21 | } 22 | 23 | size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { 24 | SWITCH_MODEL_NATIVE_STREAM(stream, fread_nfl, fread_native, ptr, size, nmemb); 25 | } 26 | 27 | size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { 28 | SWITCH_MODEL_NATIVE_STREAM(stream, fwrite_nfl, fwrite_native, ptr, size, nmemb); 29 | } 30 | 31 | int fgetc(FILE *stream) { 32 | int fd = fileno(stream); 33 | if (stream_is_casted_fd(stream) || is_nfl_sock_fd(fd)) { 34 | return fgetc_nfl(get_nfl_sock(fd)); 35 | } 36 | return fgetc_native(stream); 37 | } 38 | 39 | int fflush(FILE *stream) { 40 | if(stream == NULL) { 41 | return fflush_native(stream); 42 | } 43 | int fd = fileno(stream); 44 | if (stream_is_casted_fd(stream) || is_nfl_sock_fd(fd)) { 45 | return 0; 46 | } 47 | return fflush_native(stream); 48 | } 49 | 50 | int fclose(FILE *stream) { 51 | int fd = fileno(stream); 52 | if (stream_is_casted_fd(stream) || is_nfl_sock_fd(fd)) { 53 | return close_nfl_fd(fd); 54 | } 55 | return fclose_native(stream); 56 | } 57 | 58 | char *fgets(char *s, int size, FILE *stream) { 59 | SWITCH_MODEL_NATIVE_STREAM(stream, fgets_nfl, fgets_native, s, size); 60 | } 61 | 62 | int getc(FILE *stream) { 63 | return fgetc(stream); 64 | } 65 | 66 | int vfprintf(FILE *stream, const char *format, va_list args) { 67 | if (stream_is_casted_fd(stream) || is_nfl_sock_fd(fileno(stream))) { 68 | va_list args_copy; 69 | va_copy(args_copy, args); 70 | int buf_len = vsnprintf(NULL, 0, format, args_copy); 71 | va_end(args_copy); 72 | 73 | if (buf_len < 0) { 74 | errno = ENOBUFS; 75 | return buf_len; 76 | } 77 | char *buf = malloc(buf_len + 1); 78 | if (!buf) { 79 | errno = ENOBUFS; 80 | return -1; 81 | } 82 | 83 | int ret = vsprintf(buf, format, args); 84 | if (ret != buf_len) { 85 | free(buf); 86 | return -1; 87 | } 88 | ret = (int)write_nfl(get_nfl_sock(fileno(stream)), buf, buf_len); 89 | free(buf); 90 | return ret; 91 | } 92 | int ret = vfprintf_native(stream, format, args); 93 | return ret; 94 | } 95 | 96 | int fprintf(FILE *restrict stream, const char *restrict format, ...) { 97 | va_list args; 98 | va_start(args, format); 99 | int ret = vfprintf(stream, format, args); 100 | va_end(args); 101 | return ret; 102 | } 103 | 104 | int getchar(void) { 105 | return getc(stdin); 106 | } -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRC_FILES 2 | init.c 3 | sockets/sockets.c 4 | sockets/sockets_dgram.c 5 | sockets/sockets_stream.c 6 | sockets/sockets_rtnetlink.c 7 | sockets/poll.c 8 | sockets/sockopt.c 9 | sockets/sockets_util.c 10 | sockets/dup.c 11 | sockets/stdio.c 12 | environment/network_env.c 13 | environment/ioctl.c 14 | environment/routing.c 15 | environment/getifaddrs.c 16 | environment/import_host.c 17 | environment/util.c 18 | lib/libnl/libnl.c 19 | lib/logger/log.c 20 | hooks/hooks.c 21 | hooks/hooks-poll.c 22 | hooks/module-wrapper.c 23 | hooks/hooks-stdio.c 24 | environment/interfaces.c 25 | environment/fd_table.c) 26 | 27 | set_source_files_properties( 28 | hooks/hooks.c 29 | PROPERTIES 30 | COMPILE_FLAGS "-Wno-incompatible-pointer-types" 31 | ) 32 | 33 | set(native-call-forwarder "libc" CACHE STRING 34 | "Specify how to forward native calls to the OS, possible values: syscall-x86-64 (directly invoke syscall, only valid for x86-64 architecture), 35 | libc (forward to native c standard library)") 36 | set(possible-native-forwarders "libc;syscall-x86-64") 37 | set_property(CACHE native-call-forwarder PROPERTY STRINGS ${possible-native-forwarders}) 38 | 39 | if(${native-call-forwarder} STREQUAL syscall-x86-64) 40 | list(APPEND SRC_FILES hooks/native-syscalls-x86-64.c) 41 | message(STATUS "Native call policy: directly invoking syscall (native-call-forwarder=syscall-x86-64).") 42 | elseif(${native-call-forwarder} STREQUAL libc) 43 | list(APPEND SRC_FILES hooks/native-libc.c) 44 | message(STATUS "Native call policy: forward request to native libc (native-call-forwarder=libc).") 45 | else() 46 | message(FATAL_ERROR "Invalid native-call-forwarder, must be one of ${possible-native-forwarders}") 47 | endif() 48 | 49 | add_library(netfuzzlib SHARED ${SRC_FILES}) 50 | 51 | add_library(netfuzzlib-asan SHARED ${SRC_FILES}) 52 | target_compile_options(netfuzzlib-asan PUBLIC -fsanitize=address) 53 | target_link_options(netfuzzlib-asan PUBLIC -fsanitize=address) 54 | 55 | add_library(netfuzzlib-static STATIC ${SRC_FILES}) 56 | target_compile_definitions(netfuzzlib-static PUBLIC MODULE_STATIC_LINKED STATIC_LIBRARY) 57 | 58 | add_library(netfuzzlib-static-asan STATIC ${SRC_FILES}) 59 | target_compile_definitions(netfuzzlib-static-asan PUBLIC MODULE_STATIC_LINKED STATIC_LIBRARY) 60 | target_compile_options(netfuzzlib-static-asan PUBLIC -fsanitize=address) 61 | target_link_options(netfuzzlib-static-asan PUBLIC -fsanitize=address) 62 | 63 | set(KLEE_CFLAGS 64 | -D_FORTIFY_SOURCE=0 65 | -D_GNU_SOURCE 66 | -DDEBUG=1 67 | -DMODULE_STATIC_LINKED 68 | -Wall 69 | -Wwrite-strings 70 | -Xclang 71 | -disable-O0-optnone 72 | -DINITIALIZE_NETWORK_MODEL_MANUAL 73 | -g 74 | -I${CMAKE_SOURCE_DIR}/src 75 | -I${CMAKE_SOURCE_DIR}/modules/include) 76 | prefix_with_path("${SRC_FILES}" "${CMAKE_CURRENT_SOURCE_DIR}/" SRC_FILES_ABSOLUTE_PATH) 77 | add_bitcode_library_targets(netfuzzlib-klee "${SRC_FILES_ABSOLUTE_PATH}" "${KLEE_CFLAGS}") 78 | add_bitcode_library_targets(netfuzzlib-klee-debug "${SRC_FILES_ABSOLUTE_PATH}" "${KLEE_CFLAGS}" "-DDEBUG") -------------------------------------------------------------------------------- /test/environment/others/stdio.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" { 5 | #include "../../../include/netfuzzlib/module_api.h" 6 | #include "module.h" 7 | #include "../../../src/environment/network_env.h" 8 | } 9 | 10 | class TestEnvironmentStdio : public ::testing::Test { 11 | protected: 12 | int sockfd1; 13 | int sockfd2; 14 | 15 | void SetUp() override { 16 | init_main_library(); 17 | load_config_file("config/tcp2.conf"); 18 | 19 | struct sockaddr_in remote_addr {}; 20 | 21 | sockfd1 = socket(AF_INET, SOCK_STREAM, 0); 22 | remote_addr.sin_family = AF_INET; 23 | inet_aton("127.0.0.5", &remote_addr.sin_addr); 24 | remote_addr.sin_port = htons(5000); 25 | connect(sockfd1, reinterpret_cast(&remote_addr), sizeof(remote_addr)); 26 | 27 | sockfd2 = socket(AF_INET, SOCK_STREAM, 0); 28 | remote_addr.sin_family = AF_INET; 29 | inet_aton("127.0.0.5", &remote_addr.sin_addr); 30 | remote_addr.sin_port = htons(8000); 31 | connect(sockfd2, reinterpret_cast(&remote_addr), sizeof(remote_addr)); 32 | } 33 | }; 34 | 35 | TEST_F(TestEnvironmentStdio, testFgetCEOF) { 36 | FILE *sockfd1_stream = fdopen(sockfd1, "w"); 37 | ASSERT_TRUE(sockfd1_stream != nullptr); 38 | ASSERT_EQ(fileno(sockfd1_stream), sockfd1); 39 | 40 | int c = fgetc(sockfd1_stream); 41 | ASSERT_EQ(c, 0x06); 42 | c = fgetc(sockfd1_stream); 43 | ASSERT_EQ(c, 0x10); 44 | c = fgetc(sockfd1_stream); 45 | ASSERT_EQ(c, 0xaa); 46 | c = fgetc(sockfd1_stream); 47 | ASSERT_EQ(c, EOF); 48 | } 49 | 50 | TEST_F(TestEnvironmentStdio, testFgetCClose) { 51 | FILE *sockfd1_stream = fdopen(sockfd1, "w"); 52 | ASSERT_TRUE(sockfd1_stream != nullptr); 53 | ASSERT_EQ((long)sockfd1_stream, sockfd1); 54 | ASSERT_EQ(fileno(sockfd1_stream), sockfd1); 55 | 56 | int c = fgetc(sockfd1_stream); 57 | ASSERT_EQ(c, 0x06); 58 | 59 | c = fgetc(sockfd1_stream); 60 | ASSERT_EQ(c, 0x10); 61 | 62 | ASSERT_EQ(0, fclose(sockfd1_stream)); 63 | FILE *sockfd1_stream_copy = fdopen(sockfd1, "w"); 64 | ASSERT_EQ(nullptr, sockfd1_stream_copy); 65 | 66 | c = fgetc(sockfd1_stream); 67 | ASSERT_EQ(c, EOF); 68 | } 69 | 70 | TEST_F(TestEnvironmentStdio, testFgetsNewline) { 71 | char buf[10]{}; 72 | 73 | FILE *sockfd2_stream = fdopen(sockfd2, "w"); 74 | ASSERT_TRUE(sockfd2_stream != nullptr); 75 | ASSERT_EQ(fileno(sockfd2_stream), sockfd2); 76 | 77 | buf[1] = 10; 78 | ASSERT_EQ(fgets(buf, 2, sockfd2_stream), buf); 79 | ASSERT_EQ(buf[0], 0x01); 80 | ASSERT_EQ(buf[1], '\0'); 81 | 82 | buf[3] = 10; 83 | ASSERT_EQ(fgets(buf, 10, sockfd2_stream), buf); 84 | ASSERT_EQ(buf[0], 0x02); 85 | ASSERT_EQ(buf[1], 0x04); 86 | ASSERT_EQ(buf[2], '\n'); 87 | ASSERT_EQ(buf[3], '\0'); 88 | 89 | ASSERT_EQ(fgets(buf, 10, sockfd2_stream), nullptr); 90 | } 91 | 92 | TEST_F(TestEnvironmentStdio, testFgets2) { 93 | char buf[10]{}; 94 | 95 | FILE *sockfd1_stream = fdopen(sockfd1, "w"); 96 | ASSERT_TRUE(sockfd1_stream != nullptr); 97 | ASSERT_EQ(fileno(sockfd1_stream), sockfd1); 98 | 99 | ASSERT_EQ(fgets(buf, 10, sockfd1_stream), nullptr); 100 | } 101 | -------------------------------------------------------------------------------- /test/environment/rtnetlink/getlink/rtnetlink_getlink_single_device_filter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "rtnetlink_getlink_test_helper.h" 11 | 12 | extern "C" { 13 | #include "../../../../include/netfuzzlib/module_api.h" 14 | #include "module.h" 15 | #include "../../../../src/environment/network_env.h" 16 | } 17 | 18 | #define BUFSIZE 8192 19 | 20 | struct nl_req_s { 21 | struct nlmsghdr hdr; 22 | struct ifinfomsg gen; 23 | }; 24 | 25 | class TestRTNetlinkGetLinkSingleDeviceFilter : public ::testing::Test { 26 | protected: 27 | void SetUp() override { 28 | init_main_library(); 29 | load_config_file("config/rtnetlink-multiple-interfaces.conf"); 30 | } 31 | }; 32 | 33 | TEST_F(TestRTNetlinkGetLinkSingleDeviceFilter, test_getlink_filter_index) { 34 | struct sockaddr_nl kernel; 35 | int s, end = 0; 36 | ssize_t ret, len; 37 | struct msghdr msg; 38 | struct nl_req_s req; 39 | struct iovec io; 40 | memset(&kernel, 0, sizeof(kernel)); 41 | kernel.nl_family = AF_NETLINK; 42 | kernel.nl_groups = 0; 43 | 44 | //create a Netlink socket 45 | s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 46 | ASSERT_LT(0, s); 47 | 48 | //build netlink message 49 | memset(&req, 0, sizeof(req)); 50 | req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 51 | req.hdr.nlmsg_type = RTM_GETLINK; 52 | req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 53 | req.hdr.nlmsg_seq = 1; 54 | req.hdr.nlmsg_pid = 1000; 55 | 56 | req.gen.ifi_index = 3; 57 | 58 | memset(&io, 0, sizeof(io)); 59 | io.iov_base = &req; 60 | io.iov_len = req.hdr.nlmsg_len; 61 | 62 | memset(&msg, 0, sizeof(msg)); 63 | msg.msg_iov = &io; 64 | msg.msg_iovlen = 1; 65 | msg.msg_name = &kernel; 66 | msg.msg_namelen = sizeof(kernel); 67 | 68 | //send the message 69 | ret = sendmsg(s, &msg, 0); 70 | ASSERT_EQ(ret, io.iov_len); 71 | 72 | struct sockaddr_nl peername; 73 | socklen_t peername_len = sizeof(struct sockaddr_nl); 74 | 75 | ret = getpeername(s, (struct sockaddr *)&peername, &peername_len); 76 | ASSERT_EQ(ret, 0); 77 | ASSERT_EQ(peername.nl_family, AF_NETLINK); 78 | ASSERT_EQ(peername.nl_groups, 0); 79 | ASSERT_EQ(peername.nl_pid, 0); 80 | 81 | char buf[BUFSIZE]; 82 | memset(buf, 0, BUFSIZE); 83 | msg.msg_iov->iov_base = buf; 84 | msg.msg_iov->iov_len = BUFSIZE; 85 | 86 | len = recvmsg(s, &msg, MSG_DONTWAIT); 87 | ASSERT_LT(0, len); 88 | 89 | struct nlmsghdr *msg_ptr = (struct nlmsghdr *)buf; 90 | ASSERT_TRUE(NLMSG_OK(msg_ptr, len)); 91 | ASSERT_TRUE(msg_ptr->nlmsg_flags & NLM_F_MULTI); 92 | ASSERT_EQ(msg_ptr->nlmsg_type, RTM_NEWLINK); 93 | 94 | const unsigned char device_2_mac[] = { 0x50, 0xaa, 0x00, 0x00, 0x00, 0x00 }; 95 | const unsigned char broadcast_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 96 | test_link(msg_ptr, "device-2-eth0", (char *)device_2_mac, (char *)broadcast_mac, 1500, 4163); 97 | 98 | msg_ptr = NLMSG_NEXT(msg_ptr, len); 99 | ASSERT_FALSE(NLMSG_OK(msg_ptr, len)); 100 | close(s); 101 | } -------------------------------------------------------------------------------- /src/lib/logger/log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 rxi 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "hooks/native.h" 27 | #include "environment/network_env.h" 28 | 29 | static FILE *log_fptr = NULL; 30 | static bool use_colors = true; 31 | 32 | static struct { 33 | int level; 34 | bool quiet; 35 | } L; 36 | 37 | static const char *level_strings[] = { "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" }; 38 | static const char *level_colors[] = { "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m" }; 39 | 40 | void nfl_init_logging(char *logfile_path) { 41 | int log_fd = -1; 42 | bool close_log_fd = false; 43 | if (logfile_path) { 44 | log_fd = open(logfile_path, O_WRONLY | O_CREAT | O_APPEND, 0644); 45 | if (log_fd < 0) { 46 | log_fptr = stderr; 47 | nfl_log_error("Could not write/create log file (env NETWORK_LOG_FILE) at %s, using stderr", logfile_path); 48 | } else { 49 | close_log_fd = true; 50 | use_colors = false; 51 | } 52 | } 53 | if (log_fd < 0) { 54 | log_fd = fileno_native(stderr); 55 | } 56 | int log_fd2 = NFL_FD_LOG; 57 | dup2_native(log_fd, NFL_FD_LOG); 58 | if(close_log_fd) { 59 | close_native(log_fd); 60 | } 61 | log_fptr = fdopen(log_fd2, "a"); 62 | if (!log_fptr) { 63 | log_fptr = stderr; 64 | nfl_log_error("Could not write/create log file (env NETWORK_LOG_FILE) at %s, using stderr", logfile_path); 65 | } 66 | log_fptr = stderr; 67 | printf("test"); 68 | } 69 | 70 | void nfl_log_log(int level, const char *file, int line, const char *fmt, ...) { 71 | if (log_fptr == NULL) { 72 | nfl_init_logging(NULL); 73 | } 74 | 75 | if (L.quiet || level < L.level) { 76 | return; 77 | } 78 | 79 | char buf[16]; 80 | time_t t = time(NULL); 81 | va_list ap; 82 | va_start(ap, fmt); 83 | 84 | buf[strftime(buf, sizeof(buf), "%H:%M:%S", localtime(&t))] = '\0'; 85 | 86 | if (use_colors) { 87 | fprintf(log_fptr, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", buf, level_colors[level], level_strings[level], file, line); 88 | } else { 89 | fprintf(log_fptr, "%s %-5s %s:%d: ", buf, level_strings[level], file, line); 90 | } 91 | 92 | vfprintf(log_fptr, fmt, ap); 93 | fprintf(log_fptr, "\n"); 94 | fflush(log_fptr); 95 | 96 | va_end(ap); 97 | } 98 | -------------------------------------------------------------------------------- /test/environment/rtnetlink/getlink/rtnetlink_getlink_single_device_no_filter.cpp: -------------------------------------------------------------------------------- 1 | // RUN: %clang %s -emit-llvm -O0 -c -g -o %t1.bc 2 | // RUN: rm -rf %t.klee-out-tmp 3 | // RUN: %klee --output-dir=%t.klee-out-tmp --libc=uclibc --posix-runtime --exit-on-error %t1.bc --sym-network-no-local --sym-network-config-file %S/../rtnetlink_lo_ipv4.conf > %t.log 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define BUFSIZE 8192 18 | 19 | #include 20 | #include "rtnetlink_getlink_test_helper.h" 21 | 22 | extern "C" { 23 | #include "../../../../include/netfuzzlib/module_api.h" 24 | #include "module.h" 25 | #include "../../../../src/environment/network_env.h" 26 | } 27 | 28 | struct nl_req_s { 29 | struct nlmsghdr hdr; 30 | struct ifinfomsg gen; 31 | }; 32 | 33 | class TestRTNetlinkGetLinkSingleDeviceNoFilter : public ::testing::Test { 34 | protected: 35 | void SetUp() override { 36 | init_main_library(); 37 | load_config_file("config/empty.conf"); 38 | } 39 | }; 40 | 41 | TEST_F(TestRTNetlinkGetLinkSingleDeviceNoFilter, test_getlink_lo) { 42 | struct sockaddr_nl kernel; 43 | int s, end = 0; 44 | ssize_t ret, len; 45 | struct msghdr msg; 46 | struct nl_req_s req; 47 | struct iovec io; 48 | memset(&kernel, 0, sizeof(kernel)); 49 | kernel.nl_family = AF_NETLINK; 50 | kernel.nl_groups = 0; 51 | 52 | //create a Netlink socket 53 | s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 54 | ASSERT_LT(0, s); 55 | 56 | //build netlink message 57 | memset(&req, 0, sizeof(req)); 58 | req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 59 | req.hdr.nlmsg_type = RTM_GETLINK; 60 | req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; 61 | req.hdr.nlmsg_seq = 1; 62 | req.hdr.nlmsg_pid = 1000; 63 | 64 | req.gen.ifi_family = AF_INET6; //Should be ignored 65 | req.gen.ifi_index = 10; //Should be ignored 66 | 67 | memset(&io, 0, sizeof(io)); 68 | io.iov_base = &req; 69 | io.iov_len = req.hdr.nlmsg_len; 70 | 71 | memset(&msg, 0, sizeof(msg)); 72 | msg.msg_iov = &io; 73 | msg.msg_iovlen = 1; 74 | msg.msg_name = &kernel; 75 | msg.msg_namelen = sizeof(kernel); 76 | 77 | //send the message 78 | ret = sendmsg(s, &msg, 0); 79 | ASSERT_EQ(ret, io.iov_len); 80 | 81 | struct sockaddr_nl peername; 82 | socklen_t peername_len = sizeof(struct sockaddr_nl); 83 | 84 | ret = getpeername(s, (struct sockaddr *)&peername, &peername_len); 85 | ASSERT_EQ(ret, 0); 86 | ASSERT_EQ(peername.nl_family, AF_NETLINK); 87 | ASSERT_EQ(peername.nl_groups, 0); 88 | ASSERT_EQ(peername.nl_pid, 0); 89 | 90 | char buf[BUFSIZE]; 91 | memset(buf, 0, BUFSIZE); 92 | msg.msg_iov->iov_base = buf; 93 | msg.msg_iov->iov_len = BUFSIZE; 94 | 95 | len = recvmsg(s, &msg, MSG_DONTWAIT); 96 | ASSERT_LT(0, len); 97 | 98 | struct nlmsghdr *msg_ptr = (struct nlmsghdr *)buf; 99 | ASSERT_TRUE(NLMSG_OK(msg_ptr, len)); 100 | ASSERT_TRUE(msg_ptr->nlmsg_flags & NLM_F_MULTI); 101 | ASSERT_EQ(msg_ptr->nlmsg_type, RTM_NEWLINK); 102 | 103 | char mac_zero[ETHER_ADDR_LEN]; 104 | memset(&mac_zero, 0, sizeof(mac_zero)); 105 | 106 | test_link(msg_ptr, "lo", mac_zero, mac_zero, 65536, 73); 107 | 108 | msg_ptr = NLMSG_NEXT(msg_ptr, len); 109 | ASSERT_FALSE(NLMSG_OK(msg_ptr, len)); 110 | close(s); 111 | } 112 | -------------------------------------------------------------------------------- /modules/module-afl/module-afl-config.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "module-afl-config.h" 6 | 7 | afl_module_config *get_module_config() { 8 | static afl_module_config module_config; 9 | return &module_config; 10 | } 11 | 12 | static nfl_pkt *static_packet = NULL; 13 | 14 | nfl_pkt *get_static_packet() { 15 | return static_packet; 16 | } 17 | 18 | int load_config_ipv6(int sut_port) { 19 | static_packet = nfl_alloc_pkt(0); 20 | if (!static_packet) { 21 | nfl_log_error("Failed to allocate static packet"); 22 | return -1; 23 | } 24 | inet_pton(AF_INET6, "::1", &get_module_config()->addr_sut.s6.sin6_addr); 25 | get_module_config()->addr_sut.s6.sin6_family = AF_INET6; 26 | get_module_config()->addr_sut.s6.sin6_port = htons(sut_port); 27 | 28 | inet_pton(AF_INET6, "::1", &get_module_config()->addr_fuzzer.s6.sin6_addr); 29 | get_module_config()->addr_fuzzer.s6.sin6_family = AF_INET6; 30 | get_module_config()->addr_fuzzer.s6.sin6_port = htons(1234); 31 | return 0; 32 | } 33 | 34 | int load_config_ipv4(int sut_port) { 35 | static_packet = nfl_alloc_pkt(0); 36 | if (!static_packet) { 37 | nfl_log_error("Failed to allocate static packet"); 38 | return -1; 39 | } 40 | inet_pton(AF_INET, "127.0.0.1", &get_module_config()->addr_sut.s4.sin_addr); 41 | get_module_config()->addr_sut.s4.sin_family = AF_INET; 42 | get_module_config()->addr_sut.s4.sin_port = htons(sut_port); 43 | 44 | inet_pton(AF_INET, "127.0.0.1", &get_module_config()->addr_fuzzer.s4.sin_addr); 45 | get_module_config()->addr_fuzzer.s4.sin_family = AF_INET; 46 | get_module_config()->addr_fuzzer.s4.sin_port = htons(1234); 47 | return 0; 48 | } 49 | 50 | int load_config_ip_sut() { 51 | char *proto_str = getenv("NETFUZZLIB_AFL_PROTO"); 52 | if (!proto_str) { 53 | nfl_log_error("NETFUZZLIB_AFL_PROTO not set"); 54 | return -1; 55 | } 56 | if (strcmp(proto_str, "tcp") == 0) { 57 | get_module_config()->protocol = IPPROTO_TCP; 58 | } else if (strcmp(proto_str, "udp") == 0) { 59 | get_module_config()->protocol = IPPROTO_UDP; 60 | } else { 61 | nfl_log_error("NETFUZZLIB_AFL_PROTO must be either tcp or udp"); 62 | return -1; 63 | } 64 | 65 | char *sut_port_str = getenv("NETFUZZLIB_AFL_PORT"); 66 | if (!sut_port_str) { 67 | nfl_log_error("NETFUZZLIB_AFL_PORT not set"); 68 | return -1; 69 | } 70 | int sut_port = atoi(sut_port_str); 71 | if (sut_port == 0) { 72 | nfl_log_error("NETFUZZLIB_AFL_PORT must be a valid sut_port number"); 73 | return -1; 74 | } 75 | 76 | char *ip_version_str = getenv("NETFUZZLIB_AFL_IP_VERSION"); 77 | if (!ip_version_str || strcmp(ip_version_str, "4") == 0) { 78 | nfl_log_info("NETFUZZLIB_AFL_IP_VERSION set to 4"); 79 | return load_config_ipv4(sut_port); 80 | } else if (strcmp(ip_version_str, "6") == 0) { 81 | nfl_log_info("NETFUZZLIB_AFL_IP_VERSION set to 6"); 82 | return load_config_ipv6(sut_port); 83 | } else { 84 | nfl_log_error("NETFUZZLIB_AFL_IP_VERSION must be either 4 or 6"); 85 | return -1; 86 | } 87 | } 88 | 89 | int load_config() { 90 | get_module_config()->tcp_mode = SUT_IS_SERVER; 91 | 92 | char *persistent_mode_str = getenv("AFL_PERSISTENT"); 93 | if (!persistent_mode_str) { 94 | nfl_log_info("AFL_PERSISTENT not set"); 95 | get_module_config()->persistent_mode = false; 96 | } else { 97 | nfl_log_info("AFL_PERSISTENT set"); 98 | get_module_config()->persistent_mode = true; 99 | } 100 | 101 | return load_config_ip_sut(); 102 | } -------------------------------------------------------------------------------- /src/sockets/network_types.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_NETWORK_TYPES_H 2 | #define NETFUZZLIB_NETWORK_TYPES_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define MAX_L2_INTERFACES 20 12 | #define SOCKET_FD_START 70 // int value of the first socket file descriptor that will be used for sockets. 13 | #define SOCKET_FD_MAX 1024 // Highest possible socket file descriptor 14 | #define IS_FLAG_SET(flags, flag) ((flags) & (flag)) 15 | 16 | #define IP_OPTIONS_LEN_MAX 40 17 | 18 | typedef struct nfl_status_flags_t { 19 | bool recv_pkt_info; // True iff recvpktinfo option is set 20 | bool blocking; // True iff this is a blocking socket 21 | int rcvtimeo; // The timeout for receiving data 22 | int sndtimeo; // The timeout for sending data 23 | int tcp_fastopen; // The TCP_FASTOPEN option 24 | socklen_t ip_options_len; 25 | char ip_options[40]; // The IP_OPTIONS option 26 | } nfl_status_flags_t; 27 | 28 | /* 29 | * Holds information about an open socket fd 30 | */ 31 | typedef struct nfl_sock_t { 32 | int domain; // Network domain of the socket, see AF_INET* 33 | int type; // Socket type, see SOCK_* 34 | int protocol; // Socket protocol, see IPPROTO* 35 | 36 | nfl_addr_t *local_addr; // The local endpoint of this socket 37 | nfl_addr_t *remote_addr; // The remote endpoint of this socket 38 | 39 | struct nfl_status_flags_t status_flags; 40 | 41 | bool shutdown_read; // True iff this socket has been closed for reads 42 | bool shutdown_write; // True iff this socket has been closed for writes 43 | bool is_listening; // True iff this socket is listening for incoming stream 44 | // connections. Has no meaning if this socket is not of 45 | // type SOCK_STREAM 46 | 47 | struct nfl_pkt *packets_ll; //Buffer of currently received network data 48 | size_t packet_offset; //The offset in the packet buffer 49 | 50 | int references; // Amount of references in file descriptor table to the socket 51 | 52 | struct nfl_sock_t *tcp_pending; // The pending tcp connection, if any 53 | } nfl_sock_t; 54 | 55 | /* 56 | * Holds information about an L3 interface 57 | */ 58 | typedef struct nfl_l3_iface_t { 59 | struct nfl_l3_iface_t *next; 60 | struct nfl_l2_iface_t *parent_l2_iface; 61 | nfl_addr_t *addr; /* Address */ 62 | union { /* Netmask or prefix length */ 63 | unsigned int prefix; 64 | nfl_addr_t *netmask; 65 | }; 66 | } nfl_l3_iface_t; 67 | 68 | /* 69 | * Holds information about a network device / L2 interface 70 | */ 71 | typedef struct nfl_l2_iface_t { 72 | char name[IF_NAMESIZE + 1]; /* Name of device */ 73 | short flags; /* Flags from SIOCGIFFLAGS */ 74 | unsigned int index; 75 | char hw_addr[ETHER_ADDR_LEN]; 76 | char hw_broadcast_addr[ETHER_ADDR_LEN]; 77 | int mtu; 78 | nfl_l3_iface_t *l3_interfaces; 79 | } nfl_l2_iface_t; 80 | 81 | typedef struct ipv4_default_gateway { 82 | struct in_addr gateway_addr; 83 | nfl_l3_iface_t *interface; 84 | } ipv4_default_gateway; 85 | 86 | typedef struct ipv6_default_gateway { 87 | struct in6_addr gateway_addr; 88 | nfl_l3_iface_t *interface; 89 | } ipv6_default_gateway; 90 | 91 | /* 92 | * Wrapper type holding the current network environment. 93 | * Holds all network l2_interfaces and open sockets 94 | */ 95 | typedef struct network_env { 96 | ipv4_default_gateway *ipv4_gateway; 97 | ipv6_default_gateway *ipv6_gateway; 98 | bool enable_packet_free; 99 | nfl_sock_t *fd_table[SOCKET_FD_MAX + 1]; 100 | nfl_l2_iface_t l2_interfaces[MAX_L2_INTERFACES]; 101 | int fd_dev_null; 102 | } network_env; 103 | 104 | #endif // NETFUZZLIB_NETWORK_TYPES_H 105 | -------------------------------------------------------------------------------- /src/sockets/poll.c: -------------------------------------------------------------------------------- 1 | #include "hooks/hooks.h" 2 | #include 3 | #include "environment/network_env.h" 4 | #include "sockets_util.h" 5 | #include "sockets_stream.h" 6 | #include "environment/fd_table.h" 7 | #include 8 | 9 | bool sock_has_input_event(nfl_sock_t *sock) { 10 | if (sock->is_listening) { 11 | tcp_update_pending_connections(sock); 12 | return sock->tcp_pending != NULL; 13 | } 14 | return sock_recv_buffer_bytes_available(sock) > 0; 15 | } 16 | 17 | int poll_nfl(struct pollfd *fds, nfds_t nfds, int timeout) { 18 | nfl_log_info("poll_nfl() called with nfds=%d, timeout=%d", nfds, timeout); 19 | 20 | int amount_fds_with_event = 0; 21 | nfds_t i; 22 | nfl_sock_t *sock; 23 | 24 | for (i = 0; i < nfds; i++) { 25 | struct pollfd *current_poll_struct = &fds[i]; 26 | bool sock_has_event = false; 27 | 28 | sock = get_nfl_sock(current_poll_struct->fd); 29 | current_poll_struct->revents = 0; 30 | 31 | if (!sock) { 32 | current_poll_struct->revents |= POLLNVAL; 33 | amount_fds_with_event++; 34 | continue; 35 | } 36 | 37 | if (IS_FLAG_SET(current_poll_struct->events, POLLIN) && sock_has_input_event(sock)) { 38 | nfl_log_debug("(p)poll(): incoming data available (POLLIN) for %s\n", sock_to_str(sock)); 39 | current_poll_struct->revents |= POLLIN; 40 | sock_has_event = true; 41 | } 42 | if (IS_FLAG_SET(current_poll_struct->events, POLLOUT) && sock->remote_addr && !sock->shutdown_write) { 43 | current_poll_struct->revents |= POLLOUT; 44 | sock_has_event = true; 45 | } 46 | if (IS_FLAG_SET(current_poll_struct->events, POLLRDHUP) && sock->type == SOCK_STREAM && sock->shutdown_write) { 47 | current_poll_struct->revents |= POLLRDHUP; 48 | sock_has_event = true; 49 | } 50 | if (IS_FLAG_SET(current_poll_struct->events, POLLHUP) && sock->type == SOCK_STREAM && sock->shutdown_read) { 51 | current_poll_struct->revents |= POLLHUP; 52 | sock_has_event = true; 53 | } 54 | 55 | if (sock_has_event) 56 | amount_fds_with_event++; 57 | } 58 | 59 | nfl_log_info("poll_nfl() returning with nfds=%d, timeout=%d, amount_fds_with_event=%d", nfds, timeout, amount_fds_with_event); 60 | 61 | return amount_fds_with_event; 62 | } 63 | 64 | int select_nfl(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds) { 65 | nfl_sock_t *sock; 66 | int res = 0; 67 | bool do_read; 68 | bool do_write; 69 | bool do_except; 70 | 71 | for (int fd = 0; fd < nfds; fd++) { 72 | do_read = (readfds != NULL) && FD_ISSET(fd, readfds); 73 | do_write = (writefds != NULL) && FD_ISSET(fd, writefds); 74 | do_except = (exceptfds != NULL) && FD_ISSET(fd, exceptfds); 75 | if (!do_read && !do_write && !do_except) { 76 | continue; 77 | } 78 | 79 | sock = get_nfl_sock(fd); 80 | if (!sock) { 81 | if (do_read) { 82 | FD_CLR(fd, readfds); 83 | } 84 | if (do_except) { 85 | FD_CLR(fd, writefds); 86 | } 87 | if (do_write) { 88 | FD_CLR(fd, exceptfds); 89 | } 90 | continue; 91 | } 92 | if (do_read) { 93 | if (sock_has_input_event(sock)) { 94 | res++; 95 | } else { 96 | FD_CLR(fd, readfds); 97 | } 98 | } 99 | if (do_write) { 100 | if (sock->remote_addr && !sock->shutdown_write) { 101 | res++; 102 | } else { 103 | FD_CLR(fd, writefds); 104 | } 105 | } 106 | 107 | if (do_except) { 108 | FD_CLR(fd, exceptfds); 109 | } //No behaviour that could lead to exceptional conditions applicable to model 110 | } 111 | return res; 112 | } -------------------------------------------------------------------------------- /test/icmp/ipv6/icmpv6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | extern "C" { 11 | #include "netfuzzlib/module_api.h" 12 | #include "module.h" 13 | #include "environment/network_env.h" 14 | } 15 | 16 | struct my_in6_pktinfo { 17 | struct in6_addr ipi6_addr; /* src/dst IPv6 address */ 18 | unsigned int ipi6_ifindex; /* send/recv interface index */ 19 | }; 20 | 21 | class TestICMP : public ::testing::Test { 22 | protected: 23 | void SetUp() override { 24 | init_main_library(); 25 | load_config_file("config/icmp.conf"); 26 | } 27 | }; 28 | 29 | TEST_F(TestICMP, test_icmpv6_recvpktinfo) { 30 | int fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 31 | ASSERT_LT(0, fd); 32 | int opt = 1; 33 | ASSERT_NE(setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt)), -1); 34 | int opt_returned = 0; 35 | socklen_t opt_returned_len = sizeof(opt_returned); 36 | ASSERT_NE(getsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt_returned, &opt_returned_len), -1); 37 | ASSERT_TRUE(opt_returned); 38 | 39 | char interface_name[IF_NAMESIZE + 1]; 40 | char ipv6_address[INET6_ADDRSTRLEN]; 41 | 42 | struct msghdr msg; 43 | 44 | char packet_data[1000]; 45 | 46 | struct iovec iov; 47 | iov.iov_base = packet_data; 48 | iov.iov_len = sizeof(packet_data); 49 | 50 | char controlmsg[CMSG_SPACE(sizeof(struct my_in6_pktinfo))]; 51 | 52 | struct sockaddr_in6 from; 53 | 54 | /* Note: use outpacket for input buffer */ 55 | msg.msg_control = &controlmsg; 56 | msg.msg_controllen = sizeof(controlmsg); 57 | msg.msg_flags = 0; 58 | msg.msg_name = &from; 59 | msg.msg_namelen = sizeof(from); 60 | msg.msg_iov = &iov; //&daemon->outpacket; 61 | msg.msg_iovlen = 1; 62 | 63 | ssize_t ret = recvmsg(fd, &msg, 0); 64 | 65 | ASSERT_EQ(ret, 11); 66 | ASSERT_FALSE(msg.msg_flags & MSG_CTRUNC); 67 | struct cmsghdr *cmptr; 68 | 69 | int found_pktinfo = 0; 70 | 71 | for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) { 72 | if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == IPV6_PKTINFO) { 73 | found_pktinfo = 1; 74 | struct my_in6_pktinfo *p = (struct my_in6_pktinfo *)CMSG_DATA(cmptr); 75 | ASSERT_TRUE(p->ipi6_ifindex); //Interface indexes can't be 0; 76 | if_indextoname(p->ipi6_ifindex, interface_name); 77 | ASSERT_STREQ(interface_name, "klee-lo"); 78 | ASSERT_NE(inet_ntop(AF_INET6, &p->ipi6_addr, (char *)&ipv6_address, sizeof(ipv6_address)), nullptr); 79 | ASSERT_STREQ(ipv6_address, "::1"); 80 | }; 81 | } 82 | 83 | ASSERT_TRUE(found_pktinfo); 84 | } 85 | 86 | TEST_F(TestICMP, test_icmpv6_recvpktinfo_cmsg_buffer_to_small) { 87 | int fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 88 | ASSERT_LT(0, fd); 89 | int opt = 1; 90 | ASSERT_NE(setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt)), -1); 91 | int opt_returned = 0; 92 | socklen_t opt_returned_len = sizeof(opt_returned); 93 | ASSERT_NE(getsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt_returned, &opt_returned_len), -1); 94 | ASSERT_TRUE(opt_returned); 95 | 96 | struct msghdr msg; 97 | 98 | char packet_data[1000]; 99 | 100 | struct iovec iov; 101 | iov.iov_base = packet_data; 102 | iov.iov_len = sizeof(packet_data); 103 | 104 | char controlmsg[5]; 105 | 106 | struct sockaddr_in6 from; 107 | 108 | /* Note: use outpacket for input buffer */ 109 | msg.msg_control = &controlmsg; 110 | msg.msg_controllen = sizeof(controlmsg); 111 | msg.msg_flags = 0; 112 | msg.msg_name = &from; 113 | msg.msg_namelen = sizeof(from); 114 | msg.msg_iov = &iov; //&daemon->outpacket; 115 | msg.msg_iovlen = 1; 116 | 117 | ASSERT_EQ(recvmsg(fd, &msg, 0), 11); 118 | ASSERT_TRUE(msg.msg_flags & MSG_CTRUNC); 119 | } -------------------------------------------------------------------------------- /test/config/udp2.conf: -------------------------------------------------------------------------------- 1 | packet-format cve-concrete { 2 | char[2050]: 0x850058580000000001ff414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141 3 | } 4 | 5 | 6 | incoming-config cve { 7 | device-name: lo 8 | domain: AF_INET6 9 | type: SOCK_DGRAM 10 | protocol: IPPROTO_UDP 11 | receiver-ip: ::1 12 | receiver-port: 5000 13 | sender-ip: ::1 14 | sender-port: 6000 15 | packet-queue: cve-concrete 16 | } 17 | -------------------------------------------------------------------------------- /modules/module-afl/wait-child.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "wait-child.h" 7 | 8 | #define MAX_PIDS 10 9 | 10 | typedef struct child_state { 11 | bool assigned; 12 | pid_t pid; 13 | bool killed; 14 | int status; 15 | } child_state; 16 | 17 | static bool track_child_pids_enabled = false; 18 | static struct child_state child_pid_cache[MAX_PIDS]; 19 | static int tracked_pids = 0; 20 | 21 | void init_wait_child() { 22 | for (int i = 0; i < MAX_PIDS; i++) { 23 | memset(child_pid_cache, 0, sizeof(child_pid_cache)); 24 | } 25 | } 26 | 27 | void set_track_child_pids(bool track) { 28 | track_child_pids_enabled = track; 29 | } 30 | 31 | static int add_tracked_pid(pid_t pid) { 32 | for (int i = 0; i < MAX_PIDS; i++) { 33 | child_state *child = &child_pid_cache[i]; 34 | if (!child->assigned) { 35 | child->assigned = true; 36 | child->pid = pid; 37 | child->killed = false; 38 | child->status = 0; 39 | tracked_pids++; 40 | return 0; 41 | } 42 | } 43 | return -1; 44 | } 45 | 46 | static pid_t pop_killed_pid(int *status) { 47 | for (int i = 0; (i < MAX_PIDS) && (tracked_pids > 0); i++) { 48 | child_state *child = &child_pid_cache[i]; 49 | if (child->assigned && child->killed) { 50 | if (status) { 51 | *status = child->status; 52 | } 53 | child->assigned = false; 54 | tracked_pids--; 55 | return child->pid; 56 | } 57 | } 58 | return -1; 59 | } 60 | 61 | static pid_t find_killed_pid_or_clear(pid_t child_pid, int *status) { 62 | for (int i = 0; (i < MAX_PIDS) && (tracked_pids > 0); i++) { 63 | child_state *child = &child_pid_cache[i]; 64 | if (child->assigned && child->pid == child_pid) { 65 | child->assigned = false; 66 | tracked_pids--; 67 | if (child->killed) { 68 | if (status) { 69 | *status = child->status; 70 | } 71 | return child_pid; 72 | } 73 | return -1; 74 | } 75 | } 76 | return -1; 77 | } 78 | 79 | static pid_t fork_native() { 80 | static pid_t (*fork_libc)(void); 81 | if (!fork_libc) 82 | fork_libc = dlsym(RTLD_NEXT, "fork"); 83 | return (*fork_libc)(); 84 | } 85 | 86 | static pid_t waitpid_native(pid_t pid, int *status, int options) { 87 | static pid_t (*waitpid_libc)(pid_t, int *, int); 88 | if (!waitpid_libc) 89 | waitpid_libc = dlsym(RTLD_NEXT, "waitpid"); 90 | return (*waitpid_libc)(pid, status, options); 91 | } 92 | 93 | pid_t fork(void) { 94 | pid_t child_pid = fork_native(); 95 | if (child_pid <= 0 || !track_child_pids_enabled) 96 | return child_pid; 97 | add_tracked_pid(child_pid); 98 | return child_pid; 99 | } 100 | 101 | void wait_child_thread() { 102 | if (tracked_pids == 0) 103 | return; 104 | 105 | sigset_t sig_set; 106 | sigemptyset(&sig_set); 107 | sigaddset(&sig_set, SIGTERM); 108 | sigaddset(&sig_set, SIGCHLD); 109 | sigprocmask(SIG_BLOCK, &sig_set, NULL); 110 | 111 | for (int i = 0; i < MAX_PIDS; i++) { 112 | child_state *child = &child_pid_cache[i]; 113 | if (child->assigned && !child->killed) { 114 | waitpid_native(child->pid, &child->status, 0); 115 | child->killed = true; 116 | } 117 | } 118 | sigprocmask(SIG_UNBLOCK, &sig_set, NULL); 119 | } 120 | 121 | pid_t waitpid(pid_t pid, int *status, int options) { 122 | if (tracked_pids == 0) 123 | return waitpid_native(pid, status, options); 124 | 125 | pid_t pid_ret; 126 | if (pid < 1) { 127 | pid_ret = pop_killed_pid(status); 128 | } else { 129 | pid_ret = find_killed_pid_or_clear(pid, status); 130 | } 131 | if (pid_ret >= 0) { 132 | return pid_ret; 133 | } 134 | 135 | pid_ret = waitpid_native(pid, status, options); 136 | if (pid_ret <= 0) 137 | return pid_ret; 138 | int dummy; 139 | find_killed_pid_or_clear(pid_ret, &dummy); 140 | return pid_ret; 141 | } 142 | 143 | pid_t wait(int *status) { 144 | return waitpid(-1, status, 0); 145 | } 146 | -------------------------------------------------------------------------------- /test/udp/udp_connect.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | extern "C" { 13 | #include 14 | #include "module.h" 15 | #include "environment/network_env.h" 16 | } 17 | 18 | class TestUDPConnect : public ::testing::Test { 19 | protected: 20 | void SetUp() override { 21 | init_main_library(); 22 | load_config_file("config/udp.conf"); 23 | } 24 | }; 25 | 26 | //Check connect behaviour on udp socket 27 | TEST_F(TestUDPConnect, udp_connect) { 28 | int sockfd; 29 | char message_text[] = "Hello from server\n"; 30 | size_t message_text_len = strlen(message_text); 31 | struct sockaddr_in remote_addr_1, remote_addr_2; 32 | 33 | if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 34 | perror("socket creation failed"); 35 | exit(EXIT_FAILURE); 36 | } 37 | 38 | memset(&remote_addr_1, 0, sizeof(remote_addr_1)); 39 | memset(&remote_addr_2, 0, sizeof(remote_addr_2)); 40 | 41 | remote_addr_1.sin_family = AF_INET; // IPv4 42 | inet_pton(AF_INET, "127.0.0.2", &remote_addr_1.sin_addr.s_addr); 43 | remote_addr_1.sin_port = htons(8000); 44 | 45 | remote_addr_2.sin_family = AF_INET; // IPv4 46 | inet_pton(AF_INET, "127.0.0.3", &remote_addr_2.sin_addr.s_addr); 47 | remote_addr_2.sin_port = htons(8002); 48 | 49 | struct iovec iov[1]; 50 | iov[0].iov_base = message_text; 51 | iov[0].iov_len = message_text_len; 52 | 53 | struct msghdr message; 54 | message.msg_name = &remote_addr_1; 55 | message.msg_namelen = sizeof(remote_addr_1); 56 | message.msg_iov = iov; 57 | message.msg_iovlen = 1; 58 | message.msg_control = 0; 59 | message.msg_controllen = 0; 60 | 61 | char receive_buffer[100]; 62 | size_t receive_buffer_size = sizeof(receive_buffer); 63 | 64 | int len = sizeof(remote_addr_1); 65 | ssize_t ret; 66 | 67 | //sending on udp socket without default remote address should fail. 68 | ret = send(sockfd, (const char *)message_text, message_text_len, 0); 69 | ASSERT_EQ(ret, -1); 70 | 71 | ret = write(sockfd, (const char *)message_text, message_text_len); 72 | ASSERT_EQ(ret, -1); 73 | 74 | //Using sendto should not touch default remote address. 75 | ret = sendto(sockfd, (const char *)message_text, message_text_len, MSG_CONFIRM, (const struct sockaddr *)&remote_addr_1, len); 76 | ASSERT_EQ(ret, message_text_len); 77 | 78 | ret = send(sockfd, (const char *)message_text, message_text_len, 0); 79 | ASSERT_EQ(ret, -1); 80 | 81 | ret = write(sockfd, (const char *)message_text, message_text_len); 82 | ASSERT_EQ(ret, -1); 83 | 84 | //Using sendmsg should not touch default remote address. 85 | ret = sendmsg(sockfd, &message, 0); 86 | ASSERT_EQ(ret, message_text_len); 87 | 88 | ret = send(sockfd, (const char *)message_text, message_text_len, 0); 89 | ASSERT_EQ(ret, -1); 90 | 91 | ret = write(sockfd, (const char *)message_text, message_text_len); 92 | ASSERT_EQ(ret, -1); 93 | 94 | //Using connect should set the default remote address. 95 | ret = connect(sockfd, (const struct sockaddr *)&remote_addr_1, len); 96 | ASSERT_EQ(ret, 0); 97 | 98 | ret = send(sockfd, (const char *)message_text, message_text_len, 0); 99 | ASSERT_EQ(ret, message_text_len); 100 | 101 | ret = write(sockfd, (const char *)message_text, message_text_len); 102 | ASSERT_EQ(ret, message_text_len); 103 | 104 | //Sending to another address as the default address 105 | ret = sendto(sockfd, (const char *)message_text, message_text_len, MSG_CONFIRM, (const struct sockaddr *)&remote_addr_2, len); 106 | ASSERT_EQ(ret, message_text_len); 107 | 108 | //Calling connect with NULL parameters should remove the default address 109 | ret = connect(sockfd, NULL, 0); 110 | ASSERT_EQ(ret, 0); 111 | 112 | //Sending should fail, since there is no default address 113 | ret = send(sockfd, (const char *)message_text, message_text_len, 0); 114 | ASSERT_EQ(ret, -1); 115 | 116 | ret = write(sockfd, (const char *)message_text, message_text_len); 117 | ASSERT_EQ(ret, -1); 118 | 119 | ret = sendto(sockfd, (const char *)message_text, message_text_len, MSG_CONFIRM, (const struct sockaddr *)&remote_addr_2, len); 120 | ASSERT_EQ(ret, message_text_len); 121 | } 122 | -------------------------------------------------------------------------------- /src/environment/getifaddrs.c: -------------------------------------------------------------------------------- 1 | #include "network_env.h" 2 | #include "interfaces.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /** 10 | * Fill an ifaddrs struct (see man 3 getifaddrs) with information of an L3 network interface (nfl_l3_iface_t) 11 | * @param my_ifaddrs The ifaddrs struct to fill 12 | * @param iface_l3 The L3 network interface to use as source 13 | * @return -1 on error, 0 on success 14 | */ 15 | static int populate_ifaddrs_with_address(struct ifaddrs *my_ifaddrs, nfl_l3_iface_t *iface_l3) { 16 | memset(my_ifaddrs, 0, sizeof(struct ifaddrs)); 17 | char *name = malloc(IF_NAMESIZE + 1); 18 | if (!name) 19 | return -1; 20 | 21 | strncpy(name, iface_l3->parent_l2_iface->name, IF_NAMESIZE); 22 | my_ifaddrs->ifa_name = name; 23 | my_ifaddrs->ifa_flags = iface_l3->parent_l2_iface->flags; 24 | 25 | if (iface_l3->addr->s.sa_family == AF_INET) { 26 | struct sockaddr_in *addr_v4 = malloc(sizeof(struct sockaddr_in)); 27 | if (!addr_v4) { 28 | free(name); 29 | return -1; 30 | } 31 | struct sockaddr_in *addr_v4_netmask = malloc(sizeof(struct sockaddr_in)); 32 | if (!addr_v4_netmask) { 33 | free(name); 34 | free(addr_v4); 35 | return -1; 36 | } 37 | struct sockaddr_in *addr_v4_broadcast = malloc(sizeof(struct sockaddr_in)); 38 | if (!addr_v4_broadcast) { 39 | free(name); 40 | free(addr_v4); 41 | free(addr_v4_netmask); 42 | return -1; 43 | } 44 | 45 | memcpy(addr_v4, iface_l3->addr, sizeof(struct sockaddr_in)); 46 | memcpy(addr_v4_netmask, iface_l3->netmask, sizeof(struct sockaddr_in)); 47 | memcpy(addr_v4_broadcast, iface_l3->addr, sizeof(struct sockaddr_in)); 48 | if (!IS_FLAG_SET(iface_l3->parent_l2_iface->flags, IFF_LOOPBACK)) { 49 | // If iface_l3 is loopback iface_l3 (e.g. 127.0.0.1) ignore netmask and return iface_l3->addr (127.0.1.1) as broadcast iface_l3, same as glibc. 50 | addr_v4_broadcast->sin_addr.s_addr = addr_v4->sin_addr.s_addr | (~addr_v4_netmask->sin_addr.s_addr); 51 | } 52 | 53 | my_ifaddrs->ifa_addr = (struct sockaddr *)addr_v4; 54 | my_ifaddrs->ifa_netmask = (struct sockaddr *)addr_v4_netmask; 55 | my_ifaddrs->ifa_ifu.ifu_broadaddr = (struct sockaddr *)addr_v4_broadcast; 56 | 57 | return 0; 58 | 59 | } else if (iface_l3->addr->s.sa_family == AF_INET6) { 60 | struct sockaddr_in6 *addr_v6 = malloc(sizeof(struct sockaddr_in6)); 61 | if (!addr_v6) { 62 | free(name); 63 | return -1; 64 | } 65 | 66 | memcpy(addr_v6, iface_l3->addr, sizeof(struct sockaddr_in6)); 67 | my_ifaddrs->ifa_addr = (struct sockaddr *)addr_v6; 68 | return 0; 69 | } 70 | __builtin_unreachable(); 71 | } 72 | 73 | int getifaddrs_nfl(struct ifaddrs **ifap) { 74 | nfl_l2_iface_t *iface_l2; 75 | nfl_l3_iface_t *iface_l3; 76 | *ifap = NULL; 77 | struct ifaddrs *my_ifaddrs = NULL, *prev_ifaddrs = NULL; 78 | 79 | for (int i = 1; i < MAX_L2_INTERFACES; i++) { 80 | iface_l2 = get_l2_iface_by_index(i); 81 | if (!iface_l2) 82 | continue; 83 | for (iface_l3 = iface_l2->l3_interfaces; iface_l3; iface_l3 = iface_l3->next) { 84 | my_ifaddrs = calloc(1, sizeof(struct ifaddrs)); 85 | if (!my_ifaddrs) { 86 | errno = ENOMEM; 87 | if (*ifap) 88 | freeifaddrs(*ifap); 89 | return -1; 90 | } 91 | if (populate_ifaddrs_with_address(my_ifaddrs, iface_l3) != 0) { 92 | free(my_ifaddrs); 93 | if (*ifap) { 94 | freeifaddrs(*ifap); 95 | } 96 | return -1; 97 | } 98 | if (prev_ifaddrs) { 99 | prev_ifaddrs->ifa_next = my_ifaddrs; 100 | } else { 101 | *ifap = my_ifaddrs; 102 | } 103 | prev_ifaddrs = my_ifaddrs; 104 | } 105 | } 106 | return 0; 107 | } 108 | 109 | void freeifaddrs_nfl(struct ifaddrs *ifa) { 110 | struct ifaddrs *addrs = ifa, *prev; 111 | while (addrs) { 112 | free(addrs->ifa_name); 113 | free(addrs->ifa_addr); 114 | if (addrs->ifa_netmask) 115 | free(addrs->ifa_netmask); 116 | if (addrs->ifa_ifu.ifu_broadaddr) 117 | free(addrs->ifa_ifu.ifu_broadaddr); 118 | prev = addrs; 119 | addrs = addrs->ifa_next; 120 | free(prev); 121 | } 122 | } -------------------------------------------------------------------------------- /src/hooks/native-syscalls-x86-64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "native.h" 5 | #include "log.h" 6 | 7 | int socket_native(int domain, int type, int protocol) { 8 | return syscall(__NR_socket, domain, type, protocol); 9 | } 10 | 11 | int bind_native(int fd, const struct sockaddr *addr, socklen_t len) { 12 | return (int)syscall(__NR_bind, fd, addr, len); 13 | } 14 | 15 | int connect_native(int fd, const struct sockaddr *addr, socklen_t addrlen) { 16 | return (int)syscall(__NR_connect, fd, addr, addrlen); 17 | } 18 | 19 | int accept_native(int fd, struct sockaddr *addr, socklen_t *len) { 20 | #ifdef __NR_accept 21 | return (int)syscall(__NR_accept, fd, addr, len); 22 | #else 23 | return (int)syscall(43, fd, addr, len); 24 | #endif 25 | } 26 | 27 | int accept4_native(int fd, struct sockaddr *addr, socklen_t *len, int flags) { 28 | return (int)syscall(__NR_accept4, fd, addr, len, flags); 29 | } 30 | 31 | int getpeername_native(int fd, struct sockaddr *address, socklen_t *addrlen) { 32 | return (int)syscall(__NR_getpeername, fd, address, addrlen); 33 | } 34 | int getsockname_native(int fd, struct sockaddr *address, socklen_t *addrlen) { 35 | return (int)syscall(__NR_getsockname, fd, address, addrlen); 36 | } 37 | int getsockopt_native(int fd, int level, int option_name, void *option_value, socklen_t *option_len) { 38 | return (int)syscall(__NR_getsockopt, fd, level, option_name, option_value, option_len); 39 | } 40 | int setsockopt_native(int fd, int level, int option_name, const void *option_value, socklen_t option_len) { 41 | return (int)syscall(__NR_setsockopt, fd, level, option_name, option_value, option_len); 42 | } 43 | int listen_native(int fd, int backlog) { 44 | return (int)syscall(__NR_listen, fd, backlog); 45 | } 46 | 47 | int close_native(int fd) { 48 | return (int)syscall(__NR_close, fd); 49 | } 50 | 51 | int shutdown_native(int fd, int how) { 52 | return (int)syscall(__NR_shutdown, fd, how); 53 | } 54 | 55 | ssize_t read_native(int fd, void *buf, size_t count) { 56 | return syscall(__NR_read, fd, buf, count); 57 | } 58 | 59 | ssize_t recvfrom_native(int fd, void *buf, size_t len, int flags, struct sockaddr *remote_addr, socklen_t *addrlen) { 60 | return syscall(__NR_recvfrom, fd, buf, len, flags, remote_addr, addrlen); 61 | } 62 | ssize_t recvmsg_native(int fd, struct msghdr *msg, int flags) { 63 | return syscall(__NR_recvmsg, fd, msg, flags); 64 | } 65 | 66 | int recvmmsg_native(int fd, void *msgvec, unsigned int vlen, int flags, struct timespec *timeout) { 67 | return (int)syscall(__NR_recvmmsg, fd, msgvec, vlen, flags, timeout); 68 | } 69 | 70 | ssize_t write_native(int fd, const void *buf, size_t len) { 71 | return syscall(__NR_write, fd, buf, len); 72 | } 73 | 74 | ssize_t sendto_native(int fd, const void *buf, size_t len, int flags, const struct sockaddr *remote_addr, socklen_t addrlen) { 75 | return syscall(__NR_sendto, fd, buf, len, flags, remote_addr, addrlen); 76 | } 77 | ssize_t sendmsg_native(int fd, const struct msghdr *msg, int flags) { 78 | return syscall(__NR_sendmsg, fd, msg, flags); 79 | } 80 | 81 | int ioctl_native(int fd, unsigned long request, void *argp) { 82 | return (int)syscall(__NR_ioctl, fd, request, argp); 83 | } 84 | 85 | int poll_native(struct pollfd *fds, nfds_t nfds, int timeout) { 86 | return (int)syscall(__NR_poll, fds, nfds, timeout); 87 | } 88 | 89 | int ppoll_native(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask) { 90 | return (int)syscall(__NR_ppoll, fds, nfds, timeout_ts, sigmask); 91 | } 92 | 93 | int select_native(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { 94 | return (int)syscall(__NR_select, nfds, readfds, writefds, exceptfds, timeout); 95 | } 96 | 97 | int pselect_native(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask) { 98 | return (int)syscall(__NR_pselect6, nfds, readfds, writefds, exceptfds, timeout, sigmask); 99 | } 100 | 101 | int pipe_native(int filedes[2]) { 102 | return (int)syscall(__NR_pipe, filedes); 103 | } 104 | 105 | int fcntl_native(int fd, int cmd, ...) { 106 | va_list ap; 107 | long arg; 108 | va_start(ap, cmd); 109 | arg = va_arg(ap, long); 110 | va_end(ap); 111 | return (int)syscall(__NR_fcntl, fd, cmd, arg); 112 | } 113 | 114 | int fcntl64_native(int fd, int cmd, ...) { 115 | va_list ap; 116 | long arg; 117 | va_start(ap, cmd); 118 | arg = va_arg(ap, long); 119 | va_end(ap); 120 | #ifdef __NR_fcntl64 121 | return (int)syscall(__NR_fcntl64, fd, cmd, arg); 122 | #else 123 | return (int)syscall(221, fd, cmd, arg); 124 | } 125 | #endif 126 | } -------------------------------------------------------------------------------- /include/netfuzzlib/api.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_CONFIG_FILE_MODULE_API_PROVIDED_H 2 | #define MODULE_CONFIG_FILE_MODULE_API_PROVIDED_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define nfl_exit_log(error_code, ...) \ 10 | do { \ 11 | nfl_log_fatal(__VA_ARGS__); \ 12 | exit(error_code); \ 13 | } while (0) 14 | 15 | /** 16 | * A set of file descriptors reserved for netfuzzlib internal use. 17 | * Netfuzzlib will attempt to block the SUT from blocking file descriptors within this range 18 | * Explicit close() calls on file descriptors within this range can be done with close_native(); 19 | */ 20 | #define NFL_RESERVED_FD_START 1000 21 | #define NFL_RESERVED_FD_MODULE_START (NFL_RESERVED_FD_START + 2) // File descriptors reserved for module use 22 | #define NFL_RESERVED_FD_MAX 1010 23 | 24 | /** 25 | * Add a new network device. 26 | * @param name Must be a zero terminated string with length (including terminator) <= IF_NAMESIZE 27 | * @param flags The flags of the device, see man 7 netdevice, SIOCGIFFLAGS 28 | * @param mtu The MTU of the device 29 | * @param hw_addr The MAC address of the newly created device, size must be ETHER_ADDR_LEN 30 | * @param hw_broadcast_addr The MAC broadcast address of the newly created device, size must be ETHER_ADDR_LEN 31 | * @param device_index If successful, device_index will hold the index of the newly created device. The provided value is ignored. 32 | * @return 0 in case of success, -1 in case of failure 33 | */ 34 | int nfl_add_l2_iface(const char *name, short flags, int mtu, const char *hw_addr, const char *hw_broadcast_addr, unsigned int *device_index); 35 | 36 | /** 37 | * Add an ipv4 address to a network device. 38 | * @param device_index The index of the device to add the network interface to. 39 | * @param addr_text The IPv4 address to add in human-readable format, e.g. "192.168.1.1" 40 | * @param netmask_text The IPv4 subnet mask in human-readable format, e.g. "255.255.255.0" 41 | * @return 0 in case of success, -1 in case of failure 42 | */ 43 | int nfl_add_l3_iface_ipv4(unsigned int device_index, const char *addr_text, const char *netmask_text); 44 | 45 | /** 46 | * Add an ipv6 address to a network device. 47 | * @param device_index The index of the device to add the network interface to. 48 | * @param addr_text The IPv6 address to add in human-readable format, e.g. "2001:0000::" 49 | * @param prefix_length The network prefix length in amount of bits 50 | * @param scope The network scope, e.g. 0x0 for global or 0x20 for link 51 | * @return 0 in case of success, -1 in case of failure 52 | */ 53 | int nfl_add_l3_iface_ipv6(unsigned int device_index, const char *addr_text, int prefix_length, uint32_t scope); 54 | 55 | /** 56 | * Set the default gateway for IPv4 packets 57 | * @param gateway_addr_text "The ipv4 address of the gateway, e.g. 192.168.0.1". 58 | * Must be within the subnet of a configured address of the selected outgoing network device, or an error will be returned 59 | * @param device_index The index of the device to which packets for the default gateway will be sent. 60 | * @return 0 in case of success, -1 otherwise 61 | */ 62 | int nfl_set_ipv4_default_gateway(const char *gateway_addr_text, unsigned int device_index); 63 | 64 | /** 65 | * Set the default gateway for IPv6 packets 66 | * @param gateway_addr_text "The ipv6 address of the gateway, e.g. 2001:41d0:701:1100::1". 67 | * Must be within the subnet of a configured address of the selected outgoing network device, or an error will be returned 68 | * @param device_index The index of the device to which packets for the default gateway will be sent. 69 | * @return 0 in case of success, -1 otherwise 70 | */ 71 | int nfl_set_ipv6_default_gateway(const char *gateway_addr_text, unsigned int device_index); 72 | 73 | /** 74 | * Configure whether processed network packets should be free'd. Enabled by default. 75 | * @param free_enabled True if processed network packets should be free'd, false otherwise. 76 | */ 77 | void nfl_set_free_pkts(bool free_enabled); 78 | 79 | /** 80 | * Allocate a new network packet 81 | * @param len_bytes The size of the buffer in the packet's iovec. 82 | * @return A pointer to the new packet, or NULL if no packet could be allocated 83 | */ 84 | nfl_pkt *nfl_alloc_pkt(size_t len_bytes); 85 | 86 | /** 87 | * Normally, the model initialisation code is run before the program's entrypoint (main()) is called, 88 | * by placing it's initialisation routine in the .init section (see src/init.c). 89 | * For some applications this could interact with other instrumentation: in this case one can compile the model 90 | * with definition -DINITIALIZE_NETWORK_MODEL_MANUALLY and call nfl_init_manual() before any code of the target is executed. 91 | */ 92 | void nfl_init_manual(); 93 | 94 | #endif //MODULE_CONFIG_FILE_MODULE_API_PROVIDED_H 95 | -------------------------------------------------------------------------------- /src/sockets/sockets_util.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFUZZLIB_SOCKETS_UTIL_H 2 | #define NETFUZZLIB_SOCKETS_UTIL_H 3 | 4 | #include "network_types.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | enum ENDIANNESS { LE, BE }; 13 | 14 | /** 15 | * Update the receive buffer of a given sock. 16 | * If the buffer still has bytes available, do nothing 17 | * Otherwise, set the buffer to the next packet queued for the sock 18 | * If no packets are queued for this sock, request a new packet from the fuzzing module. 19 | * @param sock The sock for which the receive buffer should be updated. 20 | */ 21 | void sock_update_recv_buffer(nfl_sock_t *sock); 22 | 23 | /** 24 | * Get the amount of bytes available in the current packet of a sock 25 | * @param sock 26 | * @return 27 | */ 28 | size_t sock_recv_buffer_bytes_available(nfl_sock_t *sock); 29 | 30 | /** 31 | * Read data from a sock packet buffer to a given array of iovs 32 | * @param sock The sock to receive data on 33 | * @param dst_iov_array An array of iovecs 34 | * @param dst_iov_array_len The amount of iovecs in dst_iov_array 35 | * @param peek If set to true, do not remove the read data from the sock receive buffer 36 | * @return The amount of bytes read. Returns 0 if no data is available 37 | */ 38 | ssize_t socket_recv_iov(nfl_sock_t *sock, struct iovec *dst_iov_array, size_t dst_iov_array_len, bool peek); 39 | 40 | /** 41 | * Append a nfl_pkt to the end of the receive queue of a socket 42 | * @param socket The socket to add a packet to 43 | * @param packet The packet to add to the socket. Must be created with 'nfl_alloc_pkt()'. 44 | */ 45 | void sock_append_packet(nfl_sock_t *socket, nfl_pkt *packet); 46 | 47 | /** 48 | * Returns true if for the current network environment all packets have been consumed by the client application. 49 | */ 50 | bool all_packets_consumed(); 51 | 52 | /** 53 | * Free a network packet. packet->next will be ignored. 54 | */ 55 | void nfl_free_packet(nfl_pkt *packet); 56 | 57 | /** 58 | * Free a linked list of network packets. 59 | */ 60 | void free_packet_ll(nfl_pkt *packet); 61 | 62 | /** 63 | * Get the length in bytes of the sockaddr structure for a given socket domain. 64 | * E.g., returns sizeof(struct sockaddr_in) if domain == AF_INET 65 | */ 66 | socklen_t get_socket_domain_addrlen(int domain); 67 | 68 | /** 69 | * Remove and free the first queued packet in a socket and set the socket packets offset to 0 70 | * Does nothing when the passed socket does not have any packets queued 71 | * @param socket The socket to remove the current packet from 72 | */ 73 | void sock_clear_recv_buffer_and_load_next_packet(nfl_sock_t *socket); 74 | 75 | char *network_device_to_string(nfl_l2_iface_t *device); 76 | char *network_device_address_to_string(nfl_l3_iface_t *address); 77 | 78 | /** 79 | * Return whether an ipv4 address is within a given subnet 80 | * All l3_interfaces are given in network byte order. 81 | * @param network The network address 82 | * @param netmask The subnet mask of the network 83 | * @param addr The address to check whether it is in the subnet 84 | * @return True iff addr is within the subnet, e.g. addr=192.168.0.5, network=192.168.0.0 and netmask=255.255.255.0 85 | */ 86 | bool ipv4_addr_within_subnet(const struct in_addr *network, const struct in_addr *netmask, const struct in_addr *addr); 87 | 88 | /** 89 | * Return whether an ipv6 address is within a given subnet 90 | * All l3_interfaces are given in network byte order. 91 | * @param network The network address, 92 | * @param prefix The network prefix length, in bits 93 | * @param addr The address to check whether it is in the subnet 94 | * @return True iff addr is within the subnet, e.g. addr=2001::, prefix=112, addr=2001::5 95 | */ 96 | bool ipv6_addr_within_subnet(const struct in6_addr *network, unsigned int prefix, const struct in6_addr *addr); 97 | 98 | /** 99 | * Convert a nfl_sock_t to a human-readable string, for debugging purposes. 100 | * The string is returned in a statically allocated buffer, which subsequent calls will overwrite. 101 | * @param sock The socket to get debug info for. 102 | * @return A string describing the socket in human readable form. 103 | */ 104 | char *sock_to_str(const struct nfl_sock_t *sock); 105 | 106 | #define SOCKADDR_STR_MAX_LEN (INET6_ADDRSTRLEN + sizeof("|:65535")) 107 | 108 | /** 109 | * Get a sockaddr structure as a human readable string, e.g. 127.0.0.1:5555, for debugging purposes 110 | * @param addr sockaddr structure, domain can be AF_INET, AF_INET6 or AF_NETLINK 111 | * @param buf buffer to hold the resulting string 112 | * @param len The size in bytes of buf 113 | * @return buf 114 | */ 115 | char *sockaddr_to_str(const nfl_addr_t *addr, char *buf, size_t len); 116 | 117 | /** 118 | * Get a sockaddr structure as a human readable string, e.g. 127.0.0.1:5555, for debugging purposes 119 | * The string is returned in a statically allocated buffer, which subsequent calls will overwrite. 120 | * @param addr sockaddr structure, domain can be AF_INET, AF_INET6 or AF_NETLINK 121 | * @return A string describing the ip endpoint in human readable form. 122 | */ 123 | char *sockaddr_to_str_static_alloc(const nfl_addr_t *addr); 124 | 125 | #endif // NETFUZZLIB_SOCKETS_UTIL_H 126 | -------------------------------------------------------------------------------- /test/udp/ipv4/udp-ipv4-shutdown.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "udp-ipv4.h" 3 | 4 | extern "C" { 5 | #include 6 | #include "environment/network_env.h" 7 | #include 8 | #include 9 | #include 10 | } 11 | 12 | void sigpipe(int sig) { 13 | printf("Caught signal %d\n", sig); 14 | } 15 | 16 | class TestUDPv4Shutdown : public ::testing::Test { 17 | protected: 18 | void SetUp() override { 19 | #ifndef TEST_KERNEL 20 | init_main_library(); 21 | unsigned int device_index = 0; 22 | char mac_eth0[ETHER_ADDR_LEN] = { '\x01', '\x02', '\x03', '\x04', '\x05', '\x06' }; 23 | char mac_eth0_brd[ETHER_ADDR_LEN] = { '\xff', '\xff', '\xff', '\xff', '\xff', '\xff' }; 24 | nfl_add_l2_iface("not-a-real-eth0", IFF_MULTICAST | IFF_UP, 65536, mac_eth0, mac_eth0_brd, &device_index); 25 | nfl_add_l3_iface_ipv4(device_index, "192.168.0.10", "255.255.255.0"); 26 | nfl_set_ipv4_default_gateway("192.168.0.1", device_index); 27 | #endif 28 | } 29 | #ifdef TEST_KERNEL 30 | void TearDown() override { 31 | int socket_type; 32 | socklen_t length; 33 | for (int fd = 0; fd < FD_SETSIZE; fd++) { 34 | socket_type = 0; 35 | length = sizeof(socket_type); 36 | if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &socket_type, &length) == -1) { 37 | continue; 38 | } 39 | if (socket_type != SOCK_DGRAM) 40 | continue; 41 | close(fd); 42 | } 43 | } 44 | #endif 45 | }; 46 | 47 | /* Test shutdown for read and write on a freshly made socket. */ 48 | TEST_F(TestUDPv4Shutdown, shutdown) { 49 | int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 50 | if (fd < 0) 51 | FAIL() << "socket"; 52 | if (shutdown(fd, SHUT_RDWR) >= 0) 53 | FAIL() << "shutdown"; 54 | } 55 | 56 | /* Shut down for writing and then test receiving a datagram. */ 57 | TEST_F(TestUDPv4Shutdown, w_recv) { 58 | int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 59 | if (fd < 0) 60 | FAIL() << "socket"; 61 | if (shutdown(fd, SHUT_WR) >= 0) 62 | FAIL() << "shutdown"; 63 | char x; 64 | ssize_t amount = recv(fd, &x, sizeof(x), MSG_DONTWAIT); 65 | if (amount >= 0) 66 | FAIL() << "recv"; 67 | } 68 | 69 | /* Shut down for reading and then test sending a datagram. */ 70 | TEST_F(TestUDPv4Shutdown, r_send) { 71 | signal(SIGPIPE, sigpipe); 72 | int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 73 | if (fd < 0) 74 | FAIL() << "socket"; 75 | if (shutdown(fd, SHUT_RD) >= 0) 76 | FAIL() << "shutdown"; 77 | struct sockaddr_in sin {}; 78 | memset(&sin, 0, sizeof(sin)); 79 | sin.sin_family = AF_INET; 80 | sin.sin_addr.s_addr = htonl(BLACKHOLE_HOST); 81 | sin.sin_port = htons(BLACKHOLE_PORT); 82 | char x = 'x'; 83 | if (sendto(fd, &x, sizeof(x), 0, (const struct sockaddr *)&sin, sizeof(sin)) < 0) 84 | FAIL() << "sendto"; 85 | } 86 | 87 | /* Shut down for reading and writing and then test sending a datagram. */ 88 | TEST_F(TestUDPv4Shutdown, rw_send) { 89 | int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 90 | if (fd < 0) 91 | FAIL() << "socket"; 92 | if (shutdown(fd, SHUT_RDWR) >= 0) 93 | FAIL() << "shutdown"; 94 | struct sockaddr_in sin {}; 95 | memset(&sin, 0, sizeof(sin)); 96 | sin.sin_family = AF_INET; 97 | sin.sin_addr.s_addr = htonl(BLACKHOLE_HOST); 98 | sin.sin_port = htons(BLACKHOLE_PORT); 99 | char x = 'x'; 100 | if (sendto(fd, &x, sizeof(x), 0, (const struct sockaddr *)&sin, sizeof(sin)) >= 0) { 101 | FAIL() << "sendto"; 102 | } 103 | } 104 | 105 | /* Shut down for writing and then test sending a datagram. */ 106 | TEST_F(TestUDPv4Shutdown, w_send) { 107 | signal(SIGPIPE, sigpipe); 108 | int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 109 | if (fd < 0) 110 | FAIL() << "socket"; 111 | if (shutdown(fd, SHUT_WR) >= 0) 112 | FAIL() << "shutdown"; 113 | struct sockaddr_in sin {}; 114 | memset(&sin, 0, sizeof(sin)); 115 | sin.sin_family = AF_INET; 116 | sin.sin_addr.s_addr = htonl(BLACKHOLE_HOST); 117 | sin.sin_port = htons(BLACKHOLE_PORT); 118 | char x = 'x'; 119 | if (sendto(fd, &x, sizeof(x), 0, (const struct sockaddr *)&sin, sizeof(sin)) >= 0) 120 | FAIL() << "sendto"; 121 | } 122 | 123 | /* Shut down for reading and then test receiving a datagram. */ 124 | TEST_F(TestUDPv4Shutdown, r_recv) { 125 | int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 126 | if (fd < 0) 127 | FAIL() << "socket"; 128 | if (shutdown(fd, SHUT_RD) >= 0) 129 | FAIL() << "shutdown"; 130 | char x; 131 | ssize_t amount = recv(fd, &x, sizeof(x), MSG_DONTWAIT); 132 | if (amount >= 0) 133 | FAIL() << "recv"; 134 | } 135 | 136 | /* Shut down for reading and writing and then test receiving a datagram. */ 137 | TEST_F(TestUDPv4Shutdown, rw_recv) { 138 | int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 139 | if (fd < 0) 140 | FAIL() << "socket"; 141 | if (shutdown(fd, SHUT_RDWR) >= 0) 142 | FAIL() << "shutdown"; 143 | char x; 144 | ssize_t amount = recv(fd, &x, sizeof(x), MSG_DONTWAIT); 145 | if (amount >= 0) 146 | FAIL() << "recv"; 147 | else if (amount == 0) 148 | puts("EOF"); 149 | } 150 | -------------------------------------------------------------------------------- /modules/module-hello-world/module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "hooks/models.h" 7 | #include "netfuzzlib/util.h" 8 | 9 | #define HELLO_WORLD_MSG "Hello world\r\n" 10 | 11 | /** 12 | * Initialize this module, called once during environment setup. 13 | * Usually adding network interfaces happens here. 14 | */ 15 | int nfl_initialize() { 16 | unsigned int device_index = 0; 17 | char mac_eth0[ETHER_ADDR_LEN] = { '\x01', '\x02', '\x03', '\x04', '\x05', '\x06' }; 18 | char mac_eth0_brd[ETHER_ADDR_LEN] = { '\xff', '\xff', '\xff', '\xff', '\xff', '\xff' }; 19 | nfl_add_l2_iface("not-a-real-eth0", IFF_MULTICAST | IFF_UP, 65536, mac_eth0, mac_eth0_brd, &device_index); 20 | nfl_add_l3_iface_ipv4(device_index, "1.2.3.4", "255.255.255.255"); 21 | nfl_add_l3_iface_ipv6(device_index, "::1234", 128, 0x20); 22 | return 0; 23 | } 24 | 25 | /** 26 | * Define whether an attempted outgoing tcp connection should succeed 27 | * Parameters local_addr and remote_addr are guaranteed t connection. 28 | * @return True on successful connection, false otherwise. 29 | */ 30 | bool nfl_tcp_connect(const nfl_sock_module_t *sock, const nfl_addr_t *local_addr, const nfl_addr_t *remote_addr) { 31 | return true; 32 | } 33 | 34 | /** 35 | * Define an incoming tcp connection. Called when an application invokes 'accept' on a listening socket. 36 | * Parameters local_addr and remote_addr are guaranteed to be of same type, sockaddr_in or sockaddr_in6 37 | * @param local_addr The local address bound to the socket. 38 | * @param remote_addr The address of the remote endpoint. This must be initialized by the module in case the connection was successful. 39 | * @return True on successful connection, false otherwise. 40 | */ 41 | bool nfl_tcp_accept(const nfl_sock_module_t *sock, const nfl_addr_t *local_addr, nfl_addr_t *remote_addr) { 42 | static int amount_incoming_connections_left = 10; 43 | if (amount_incoming_connections_left <= 0) 44 | return false; 45 | 46 | amount_incoming_connections_left--; 47 | if (sock->domain == AF_INET) { 48 | remote_addr->s4.sin_family = AF_INET; 49 | remote_addr->s4.sin_port = htons(5678); 50 | inet_pton(AF_INET, "1.2.3.4", &remote_addr->s4.sin_addr); 51 | } else if (sock->domain == AF_INET6) { 52 | remote_addr->s6.sin6_family = AF_INET6; 53 | remote_addr->s6.sin6_port = htons(5678); 54 | inet_pton(AF_INET6, "::1234", &remote_addr->s6.sin6_addr); 55 | } 56 | return true; 57 | } 58 | 59 | /** 60 | * Called when an application attempts to send data on a network socket 61 | * @param sock The socket on which a send call was issued 62 | * @param from The sender address of the packet, type sockaddr_in | sockaddr_in6 63 | * @param to The destination address of the packet, type sockaddr_in | sockaddr_in6 64 | * @param iov Array of iovec structs containing the outgoing data 65 | * @param iovlen The amount of iovec structs in the array 66 | * @return The amount of bytes sent, or a negative value in case of an error 67 | */ 68 | ssize_t nfl_send(const nfl_sock_module_t *sock, const nfl_addr_t *from, const nfl_addr_t *to, struct iovec *iov, size_t iovlen) { 69 | return iov_count_bytes(iov, iovlen); 70 | } 71 | 72 | /** 73 | * Called when an application attempts to read data on a network sock, and the current buffer is empty 74 | * @param sock The sock on which a read call was issued 75 | * @param bound_addr The address bound to the sock, type sockaddr_in | sockaddr_in6 76 | * @param packet Packet which must be allocated and initialized by the network environment, see nfl_alloc_pkt() in module_provided.h 77 | * Must remain unaltered if no packet has been received. 78 | * For TCP only the iov field needs to be filled in, other fields are ignored. 79 | */ 80 | nfl_pkt *nfl_receive(const nfl_sock_module_t *sock, const nfl_addr_t *bound_addr) { 81 | static int amount_packets_left = 10; 82 | if (amount_packets_left <= 0) { 83 | if (sock->protocol == IPPROTO_TCP) { 84 | shutdown_nfl((nfl_sock_t *)sock, SHUT_RDWR); 85 | } 86 | return NULL; 87 | } 88 | amount_packets_left--; 89 | nfl_pkt *packet = nfl_alloc_pkt(sizeof(HELLO_WORLD_MSG)); 90 | if (!packet) { 91 | return NULL; 92 | } 93 | strcpy(packet->iov.iov_base, HELLO_WORLD_MSG); 94 | 95 | packet->device_index = 1; 96 | if (sock->domain == AF_INET) { 97 | inet_pton(AF_INET, "127.0.0.1", &packet->local_addr.s4.sin_addr); 98 | inet_pton(AF_INET, "127.0.0.1", &packet->remote_addr.s4.sin_addr); 99 | 100 | packet->local_addr.s4.sin_family = packet->remote_addr.s4.sin_family = AF_INET; 101 | packet->local_addr.s4.sin_port = bound_addr->s4.sin_port; 102 | packet->remote_addr.s4.sin_port = htons(9999); 103 | return packet; 104 | } else if (sock->domain == AF_INET6) { 105 | inet_pton(AF_INET6, "::1", &packet->local_addr.s6.sin6_addr); 106 | inet_pton(AF_INET6, "::1", &packet->remote_addr.s6.sin6_addr); 107 | 108 | packet->local_addr.s6.sin6_family = packet->remote_addr.s6.sin6_family = AF_INET6; 109 | packet->local_addr.s6.sin6_port = bound_addr->s6.sin6_port; 110 | packet->remote_addr.s6.sin6_port = htons(9999); 111 | return packet; 112 | } 113 | return NULL; 114 | } 115 | -------------------------------------------------------------------------------- /test/environment/rtnetlink/getaddr/rtnetlink_getaddr_single_interface.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | extern "C" { 10 | #include "../../../../include/netfuzzlib/module_api.h" 11 | #include "module.h" 12 | #include "../../../../src/environment/network_env.h" 13 | } 14 | 15 | #define BUFSIZE 8192 16 | 17 | struct nl_req_s { 18 | struct nlmsghdr hdr; 19 | struct rtgenmsg gen; 20 | }; 21 | 22 | class TestRTNetlinkSingleInterface : public ::testing::Test { 23 | protected: 24 | void SetUp() override { 25 | init_main_library(); 26 | load_config_file("config/empty.conf"); 27 | } 28 | }; 29 | 30 | static void check_addr(struct nlmsghdr *hdr) { 31 | struct ifaddrmsg *addr; 32 | struct rtattr *attr; 33 | unsigned long len; 34 | 35 | addr = (struct ifaddrmsg *)NLMSG_DATA(hdr); 36 | len = hdr->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr)) - NLMSG_ALIGN(sizeof(struct ifaddrmsg)); 37 | 38 | assert(addr->ifa_family == AF_INET); 39 | assert(addr->ifa_prefixlen == 8); 40 | assert(addr->ifa_scope == RT_SCOPE_HOST); 41 | assert(addr->ifa_index == 1); 42 | assert(addr->ifa_flags == IFA_F_PERMANENT); 43 | 44 | bool ifa_label_seen = false, ifa_local_seen = false, ifa_address_seen = false, ifa_broadcast_seen = false, ifa_flags_seen = false, 45 | ifa_cacheinfo_seen = false; 46 | 47 | int attr_count = 0; 48 | for (attr = IFA_RTA(addr); RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) { 49 | attr_count++; 50 | switch (attr->rta_type) { 51 | case IFA_LABEL: 52 | ifa_label_seen = true; 53 | ASSERT_STREQ((char *)RTA_DATA(attr), "lo"); 54 | break; 55 | case IFA_LOCAL: { 56 | ifa_local_seen = true; 57 | assert(*(in_addr_t *)RTA_DATA(attr) == inet_addr("127.0.0.1")); 58 | break; 59 | } 60 | case IFA_ADDRESS: { 61 | ifa_address_seen = true; 62 | assert(*(in_addr_t *)RTA_DATA(attr) == inet_addr("127.0.0.1")); 63 | break; 64 | } 65 | case IFA_BROADCAST: { 66 | ifa_broadcast_seen = true; 67 | assert(*(in_addr_t *)RTA_DATA(attr) == inet_addr("127.255.255.255")); 68 | break; 69 | } 70 | case IFA_FLAGS: { 71 | ifa_flags_seen = true; 72 | assert(*(int *)RTA_DATA(attr) == IFA_F_PERMANENT); 73 | break; 74 | } 75 | case IFA_CACHEINFO: { 76 | ifa_cacheinfo_seen = true; 77 | struct ifa_cacheinfo *cacheinfo = (struct ifa_cacheinfo *)RTA_DATA(attr); 78 | assert(cacheinfo->tstamp == 20000); 79 | assert(cacheinfo->cstamp == 10000); 80 | assert(cacheinfo->ifa_valid == 3000); 81 | assert(cacheinfo->ifa_prefered == 3000); 82 | break; 83 | } 84 | default: 85 | assert(0 && "Unknown flags!"); 86 | break; 87 | } 88 | } 89 | ASSERT_TRUE(ifa_label_seen); 90 | ASSERT_TRUE(ifa_local_seen); 91 | ASSERT_TRUE(ifa_address_seen); 92 | ASSERT_TRUE(ifa_broadcast_seen); 93 | ASSERT_TRUE(ifa_flags_seen); 94 | ASSERT_TRUE(ifa_cacheinfo_seen); 95 | ASSERT_EQ(attr_count, 6); 96 | } 97 | 98 | TEST_F(TestRTNetlinkSingleInterface, test_getaddr_single_interface) { 99 | struct sockaddr_nl kernel; 100 | int s, end = 0; 101 | ssize_t ret, len; 102 | struct msghdr msg; 103 | struct nl_req_s req; 104 | struct iovec io; 105 | memset(&kernel, 0, sizeof(kernel)); 106 | kernel.nl_family = AF_NETLINK; 107 | kernel.nl_groups = 0; 108 | 109 | //create a Netlink socket 110 | s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 111 | ASSERT_LT(0, s); 112 | 113 | //build netlink message 114 | memset(&req, 0, sizeof(req)); 115 | req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); 116 | req.hdr.nlmsg_type = RTM_GETADDR; 117 | req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 118 | req.hdr.nlmsg_seq = 1; 119 | req.hdr.nlmsg_pid = 1000; 120 | req.gen.rtgen_family = 0; 121 | 122 | memset(&io, 0, sizeof(io)); 123 | io.iov_base = &req; 124 | io.iov_len = req.hdr.nlmsg_len; 125 | 126 | memset(&msg, 0, sizeof(msg)); 127 | msg.msg_iov = &io; 128 | msg.msg_iovlen = 1; 129 | msg.msg_name = &kernel; 130 | msg.msg_namelen = sizeof(kernel); 131 | 132 | //send the message 133 | ret = sendmsg(s, &msg, 0); 134 | ASSERT_EQ(ret, io.iov_len); 135 | 136 | struct sockaddr_nl peername; 137 | socklen_t peername_len = sizeof(struct sockaddr_nl); 138 | 139 | ret = getpeername(s, (struct sockaddr *)&peername, &peername_len); 140 | ASSERT_EQ(ret, 0); 141 | ASSERT_EQ(peername.nl_family, AF_NETLINK); 142 | ASSERT_EQ(peername.nl_groups, 0); 143 | ASSERT_EQ(peername.nl_pid, 0); 144 | 145 | char buf[BUFSIZE]; 146 | memset(buf, 0, BUFSIZE); 147 | msg.msg_iov->iov_base = buf; 148 | msg.msg_iov->iov_len = BUFSIZE; 149 | len = recvmsg(s, &msg, MSG_DONTWAIT); 150 | ASSERT_GT(len, 0); 151 | 152 | struct nlmsghdr *msg_ptr = (struct nlmsghdr *)buf; 153 | ASSERT_TRUE(NLMSG_OK(msg_ptr, len)); 154 | ASSERT_TRUE(msg_ptr->nlmsg_flags & NLM_F_MULTI); 155 | ASSERT_EQ(msg_ptr->nlmsg_type, RTM_NEWADDR); 156 | check_addr(msg_ptr); 157 | msg_ptr = NLMSG_NEXT(msg_ptr, len); 158 | ASSERT_FALSE(NLMSG_OK(msg_ptr, len)); 159 | 160 | close(s); 161 | } 162 | -------------------------------------------------------------------------------- /test/environment/rtnetlink/getlink/rtnetlink_getlink_all_devices.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include "rtnetlink_getlink_test_helper.h" 15 | 16 | extern "C" { 17 | #include "../../../../include/netfuzzlib/module_api.h" 18 | #include "module.h" 19 | #include "../../../../src/environment/network_env.h" 20 | } 21 | 22 | #define BUFSIZE 8192 23 | 24 | struct nl_req_s { 25 | struct nlmsghdr hdr; 26 | struct ifinfomsg gen; 27 | }; 28 | 29 | class TestRTNetlinkGetLinkAllDevices : public ::testing::Test { 30 | protected: 31 | void SetUp() override { 32 | init_main_library(); 33 | load_config_file("config/rtnetlink-multiple-interfaces.conf"); 34 | } 35 | }; 36 | 37 | TEST_F(TestRTNetlinkGetLinkAllDevices, test_getlink_all) { 38 | struct sockaddr_nl kernel; 39 | int s, end = 0; 40 | ssize_t ret, len; 41 | struct msghdr msg; 42 | struct nl_req_s req; 43 | struct iovec io; 44 | memset(&kernel, 0, sizeof(kernel)); 45 | kernel.nl_family = AF_NETLINK; 46 | kernel.nl_groups = 0; 47 | 48 | //create a Netlink socket 49 | s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 50 | ASSERT_GT(s, 0); 51 | 52 | //build netlink message 53 | memset(&req, 0, sizeof(req)); 54 | req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 55 | req.hdr.nlmsg_type = RTM_GETLINK; 56 | req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; 57 | req.hdr.nlmsg_seq = 1; 58 | req.hdr.nlmsg_pid = 1000; 59 | 60 | req.gen.ifi_family = AF_INET6; //Should be ignored 61 | req.gen.ifi_index = 10; //Should be ignored 62 | 63 | memset(&io, 0, sizeof(io)); 64 | io.iov_base = &req; 65 | io.iov_len = req.hdr.nlmsg_len; 66 | 67 | memset(&msg, 0, sizeof(msg)); 68 | msg.msg_iov = &io; 69 | msg.msg_iovlen = 1; 70 | msg.msg_name = &kernel; 71 | msg.msg_namelen = sizeof(kernel); 72 | 73 | //send the message 74 | ret = sendmsg(s, &msg, 0); 75 | ASSERT_EQ(ret, io.iov_len); 76 | 77 | struct sockaddr_nl peername; 78 | socklen_t peername_len = sizeof(struct sockaddr_nl); 79 | 80 | ret = getpeername(s, (struct sockaddr *)&peername, &peername_len); 81 | ASSERT_EQ(ret, 0); 82 | ASSERT_EQ(peername.nl_family, AF_NETLINK); 83 | ASSERT_EQ(peername.nl_groups, 0); 84 | ASSERT_EQ(peername.nl_pid, 0); 85 | 86 | char buf[BUFSIZE]; 87 | 88 | int msg_count = 0; 89 | bool done = false; 90 | bool device_1_seen = false, device_2_seen = false, device_3_seen = false, device_lo_seen = false; 91 | 92 | while (!done) { 93 | memset(buf, 0, BUFSIZE); 94 | msg.msg_iov->iov_base = buf; 95 | msg.msg_iov->iov_len = BUFSIZE; 96 | len = recvmsg(s, &msg, MSG_DONTWAIT); 97 | ASSERT_GT(len, 0); 98 | const unsigned char broadcast_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 99 | 100 | for (struct nlmsghdr *msg_ptr = (struct nlmsghdr *)buf; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) { 101 | msg_count++; 102 | ASSERT_TRUE(msg_ptr->nlmsg_flags & NLM_F_MULTI); 103 | switch (msg_ptr->nlmsg_type) { 104 | case NLMSG_DONE: { 105 | done = true; 106 | break; 107 | } 108 | case RTM_NEWLINK: { 109 | struct ifinfomsg *ifinfo = (struct ifinfomsg *)NLMSG_DATA(msg_ptr); 110 | if (ifinfo->ifi_index == 1) { 111 | device_lo_seen = true; 112 | const unsigned char lo_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 113 | test_link(msg_ptr, "lo", reinterpret_cast(lo_mac), reinterpret_cast(lo_mac), 65536, 73); 114 | } else if (ifinfo->ifi_index == 2) { 115 | device_1_seen = true; 116 | const unsigned char device_1_mac[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x00 }; 117 | test_link(msg_ptr, "device-1-no-l3", reinterpret_cast(device_1_mac), reinterpret_cast(broadcast_mac), 65536, 118 | 73); 119 | } else if (ifinfo->ifi_index == 3) { 120 | device_2_seen = true; 121 | const unsigned char device_3_mac[] = { 0x50, 0xaa, 0x00, 0x00, 0x00, 0x00 }; 122 | test_link(msg_ptr, "device-2-eth0", reinterpret_cast(device_3_mac), reinterpret_cast(broadcast_mac), 1500, 123 | 4163); 124 | } else if (ifinfo->ifi_index == 4) { 125 | device_3_seen = true; 126 | const unsigned char device_4_mac[] = { 0x60, 0xaa, 0x00, 0x00, 0x00, 0x00 }; 127 | test_link(msg_ptr, "device-3-eth1", reinterpret_cast(device_4_mac), reinterpret_cast(broadcast_mac), 1500, 128 | 4163); 129 | } else { 130 | nfl_log_fatal("Unknown index"); 131 | FAIL(); 132 | } 133 | continue; 134 | } 135 | default: 136 | nfl_log_fatal("Received unknown message type"); 137 | FAIL(); 138 | } 139 | } 140 | ASSERT_EQ(len, 0); 141 | } 142 | 143 | ASSERT_TRUE(device_1_seen); 144 | ASSERT_TRUE(device_2_seen); 145 | ASSERT_TRUE(device_3_seen); 146 | ASSERT_TRUE(device_lo_seen); 147 | 148 | ASSERT_EQ(msg_count, 5); 149 | close(s); 150 | } 151 | -------------------------------------------------------------------------------- /test/environment/routing/routing.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | extern "C" { 7 | #include "sockets/sockets_util.h" 8 | #include "environment/network_env.h" 9 | #include "module.h" 10 | }; 11 | 12 | class TestRouting : public ::testing::Test { 13 | protected: 14 | void SetUp() override { 15 | init_main_library(); 16 | load_config_file("config/routing-gateway.conf"); 17 | } 18 | }; 19 | 20 | static void test_udp_connect_ipv4(const char *addr_to_connect, const char *expected_bound_addr) { 21 | int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 22 | 23 | struct sockaddr_in addr {}; 24 | addr.sin_family = AF_INET; 25 | inet_aton(addr_to_connect, &addr.sin_addr); 26 | addr.sin_port = htons(53); 27 | 28 | //Sets the default remote endpoint of the UDP socket 29 | //This will be used when e.g. calling write() 30 | int err = connect(fd, reinterpret_cast(&addr), sizeof(addr)); 31 | ASSERT_EQ(err, 0); 32 | 33 | struct sockaddr_in bound_address {}; 34 | socklen_t size = sizeof(struct sockaddr_in); 35 | getsockname(fd, reinterpret_cast(&bound_address), &size); 36 | char *addr_string = inet_ntoa(bound_address.sin_addr); 37 | ASSERT_STREQ(addr_string, expected_bound_addr); 38 | close(fd); 39 | } 40 | 41 | static void test_udp_connect_ipv6(const char *addr_to_connect, const char *expected_bound_addr) { 42 | int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 43 | 44 | struct sockaddr_in6 addr {}; 45 | addr.sin6_family = AF_INET6; 46 | inet_pton(AF_INET6, addr_to_connect, &addr.sin6_addr); 47 | addr.sin6_port = htons(53); 48 | 49 | //Sets the default remote endpoint of the UDP socket 50 | //This will be used when e.g. calling write() 51 | int err = connect(fd, reinterpret_cast(&addr), sizeof(addr)); 52 | ASSERT_EQ(err, 0); 53 | 54 | struct sockaddr_in6 bound_address {}; 55 | socklen_t size = sizeof(struct sockaddr_in6); 56 | getsockname(fd, reinterpret_cast(&bound_address), &size); 57 | char addr_string[INET6_ADDRSTRLEN] = {}; 58 | inet_ntop(AF_INET6, &bound_address.sin6_addr, addr_string, INET6_ADDRSTRLEN); 59 | ASSERT_STREQ(addr_string, expected_bound_addr); 60 | close(fd); 61 | } 62 | 63 | TEST_F(TestRouting, test_udp_ipv4_connect) { 64 | test_udp_connect_ipv4("127.0.0.5", "127.0.0.1"); 65 | test_udp_connect_ipv4("127.1.0.5", "127.0.0.1"); 66 | test_udp_connect_ipv4("10.0.0.10", "10.0.0.5"); 67 | test_udp_connect_ipv4("10.0.0.5", "10.0.0.5"); 68 | test_udp_connect_ipv4("192.168.1.10", "192.168.1.2"); 69 | test_udp_connect_ipv4("192.168.1.2", "192.168.1.2"); 70 | test_udp_connect_ipv4("192.168.10.1", "10.0.0.5"); 71 | test_udp_connect_ipv4("91.34.10.2", "91.34.10.2"); 72 | test_udp_connect_ipv4("8.8.8.8", "10.0.0.5"); 73 | } 74 | 75 | TEST_F(TestRouting, test_udp_ipv6_connect) { 76 | test_udp_connect_ipv6("::1", "::1"); 77 | test_udp_connect_ipv6("2a02::3183:a900:5b63:0019:ab00:c679", "2a02:0:3183:a900:5b63:19:ab00:c679"); 78 | test_udp_connect_ipv6("2a02::3183:a900:5b63:0019:ab00:c680", "2a02:0:3183:a900:5b63:19:ab00:c679"); 79 | test_udp_connect_ipv6("2a02::3183:a900:5b64:0019:ab00:c681", "2a02:0:3183:a900:5b63:19:ab00:c679"); 80 | test_udp_connect_ipv6("2a02::3183:a900:5b63:0020:ab00:c679", "2a02:0:3183:a900:5b63:19:ab00:c679"); 81 | test_udp_connect_ipv6("2a02::3183:a900:5b63:0020:ab00:c679", "2a02:0:3183:a900:5b63:19:ab00:c679"); 82 | 83 | test_udp_connect_ipv6("fe80::5859:71af:177e:db7a", "fe80::5859:71af:177e:db7a"); 84 | test_udp_connect_ipv6("fe80::5859:71af:177e:db8a", "fe80::5859:71af:177e:db7a"); 85 | test_udp_connect_ipv6("fe80::5859:72af:177e:db7a", "fe80::5859:71af:177e:db7a"); 86 | } 87 | 88 | TEST_F(TestRouting, ipv6_addr_within_subnet) { 89 | struct in6_addr addr1; 90 | struct in6_addr addr2; 91 | inet_pton(AF_INET6, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", &addr1); 92 | inet_pton(AF_INET6, "2001:0db8:85a3:0000:0100:8a2e:0370:7334", &addr2); 93 | ASSERT_TRUE(ipv6_addr_within_subnet(&addr1, 128, &addr1)); 94 | ASSERT_FALSE(ipv6_addr_within_subnet(&addr1, 128, &addr2)); 95 | ASSERT_TRUE(ipv6_addr_within_subnet(&addr1, 64, &addr2)); 96 | ASSERT_FALSE(ipv6_addr_within_subnet(&addr1, 72, &addr2)); 97 | 98 | inet_pton(AF_INET6, "2000:0000:0000:0000:0000:0000:0000:0000", &addr2); 99 | ASSERT_TRUE(ipv6_addr_within_subnet(&addr1, 10, &addr2)); 100 | inet_pton(AF_INET6, "203f:ffff:ffff:ffff:ffff:ffff:ffff:ffff", &addr2); 101 | ASSERT_TRUE(ipv6_addr_within_subnet(&addr1, 10, &addr2)); 102 | inet_pton(AF_INET6, "2040::", &addr2); 103 | ASSERT_FALSE(ipv6_addr_within_subnet(&addr1, 10, &addr2)); 104 | 105 | inet_pton(AF_INET6, "2001:0db8:85a3:0000:0000:8a2e:0370:7333", &addr2); 106 | ASSERT_FALSE(ipv6_addr_within_subnet(&addr1, 127, &addr2)); 107 | inet_pton(AF_INET6, "2001:0db8:85a3:0000:0000:8a2e:0370:7335", &addr2); 108 | ASSERT_TRUE(ipv6_addr_within_subnet(&addr1, 127, &addr2)); 109 | inet_pton(AF_INET6, "2001:0db8:85a3:0000:0000:8a2e:0370:7336", &addr2); 110 | ASSERT_FALSE(ipv6_addr_within_subnet(&addr1, 127, &addr2)); 111 | 112 | inet_pton(AF_INET6, "0000:0000:0000:0000:0000:0000:0000:0000", &addr2); 113 | ASSERT_TRUE(ipv6_addr_within_subnet(&addr1, 1, &addr2)); 114 | inet_pton(AF_INET6, "7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", &addr2); 115 | ASSERT_TRUE(ipv6_addr_within_subnet(&addr1, 1, &addr2)); 116 | inet_pton(AF_INET6, "8000:0000:0000:0000:0000:0000:0000:0000", &addr2); 117 | ASSERT_FALSE(ipv6_addr_within_subnet(&addr1, 1, &addr2)); 118 | inet_pton(AF_INET6, "8fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", &addr2); 119 | ASSERT_FALSE(ipv6_addr_within_subnet(&addr1, 1, &addr2)); 120 | } -------------------------------------------------------------------------------- /test/udp/ipv4/udp-ipv4-send.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" { 5 | #include 6 | #include "environment/network_env.h" 7 | #include 8 | #include 9 | #include 10 | } 11 | #define BLACKHOLE_HOST "8.8.8.8" 12 | #define BLACKHOLE_PORT 53 13 | 14 | class TestUDPv4Send : public ::testing::Test { 15 | protected: 16 | void SetUp() override { 17 | #ifndef TEST_KERNEL 18 | init_main_library(); 19 | unsigned int device_index = 0; 20 | char mac_eth0[ETHER_ADDR_LEN] = { '\x01', '\x02', '\x03', '\x04', '\x05', '\x06' }; 21 | char mac_eth0_brd[ETHER_ADDR_LEN] = { '\xff', '\xff', '\xff', '\xff', '\xff', '\xff' }; 22 | nfl_add_l2_iface("not-a-real-eth0", IFF_MULTICAST | IFF_UP, 65536, mac_eth0, mac_eth0_brd, &device_index); 23 | nfl_add_l3_iface_ipv4(device_index, "192.168.0.10", "255.255.255.0"); 24 | nfl_set_ipv4_default_gateway("192.168.0.1", device_index); 25 | #endif 26 | } 27 | #ifdef TEST_KERNEL 28 | void TearDown() override { 29 | int socket_type; 30 | socklen_t length; 31 | for (int fd = 0; fd < FD_SETSIZE; fd++) { 32 | socket_type = 0; 33 | length = sizeof(socket_type); 34 | if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &socket_type, &length) == -1) { 35 | continue; 36 | } 37 | if (socket_type != SOCK_DGRAM) 38 | continue; 39 | close(fd); 40 | } 41 | } 42 | #endif 43 | }; 44 | 45 | /* Test sending a datagram without a specified destination. */ 46 | TEST_F(TestUDPv4Send, sendto_null) { 47 | int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 48 | if (fd < 0) 49 | FAIL() << "socket"; 50 | char x = 'x'; 51 | if (sendto(fd, &x, sizeof(x), 0, nullptr, 0) >= 0) 52 | FAIL() << "sendto"; 53 | usleep(50000); 54 | int errnum; 55 | socklen_t errnumlen = sizeof(errnum); 56 | if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errnum, &errnumlen) < 0) 57 | FAIL() << "getsockopt: SO_ERROR"; 58 | if (errnum) { 59 | errno = errnum; 60 | FAIL() << "SO_ERROR"; 61 | } 62 | } 63 | 64 | /* Test sending a datagram to the any address. */ 65 | TEST_F(TestUDPv4Send, sendto_any_so_error) { 66 | int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 67 | if (fd < 0) 68 | FAIL() << "socket"; 69 | struct sockaddr_in sin {}; 70 | memset(&sin, 0, sizeof(sin)); 71 | sin.sin_family = AF_INET; 72 | sin.sin_addr.s_addr = htonl(INADDR_ANY); 73 | sin.sin_port = htons(65535); 74 | char x = 'x'; 75 | if (sendto(fd, &x, sizeof(x), 0, (const struct sockaddr *)&sin, sizeof(sin)) < 0) 76 | FAIL() << "sendto"; 77 | usleep(50000); 78 | int errnum; 79 | socklen_t errnumlen = sizeof(errnum); 80 | if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errnum, &errnumlen) < 0) 81 | FAIL() << "getsockopt: SO_ERROR"; 82 | if (errnum) { 83 | errno = errnum; 84 | FAIL() << "SO_ERROR"; 85 | } 86 | } 87 | 88 | /* Send a datagram to loopback address port 65535 and then test the local 89 | address. */ 90 | TEST_F(TestUDPv4Send, sendto_getsockname) { 91 | int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 92 | if (fd < 0) 93 | FAIL() << "socket"; 94 | struct sockaddr_in sin {}; 95 | memset(&sin, 0, sizeof(sin)); 96 | sin.sin_family = AF_INET; 97 | sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 98 | sin.sin_port = htons(65535); 99 | char x = 'x'; 100 | if (sendto(fd, &x, sizeof(x), 0, (const struct sockaddr *)&sin, sizeof(sin)) < 0) 101 | FAIL() << "sendto"; 102 | struct sockaddr_in local {}; 103 | socklen_t locallen = sizeof(local); 104 | if (getsockname(fd, (struct sockaddr *)&local, &locallen) < 0) 105 | FAIL() << "getsockname"; 106 | char host[INET_ADDRSTRLEN + 1]; 107 | char port[5 + 1]; 108 | getnameinfo((const struct sockaddr *)&local, locallen, host, sizeof(host), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); 109 | if (!strncmp(host, "192.168.", strlen("192.168."))) 110 | printf("192.168.1.x"); 111 | else if (!strncmp(host, "100.82.", strlen("100.82."))) 112 | printf("192.168.1.x"); 113 | else 114 | printf("%s", host); 115 | printf(":"); 116 | if (!strcmp(port, "0")) 117 | printf("%s", port); 118 | else 119 | printf("non-zero"); 120 | printf("\n"); 121 | } 122 | 123 | /* Test sending a datagram without a specified destination. */ 124 | TEST_F(TestUDPv4Send, send) { 125 | int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 126 | if (fd < 0) 127 | FAIL() << "socket"; 128 | char x = 'x'; 129 | if (send(fd, &x, sizeof(x), 0) >= 0) 130 | FAIL() << "send"; 131 | usleep(50000); 132 | int errnum; 133 | socklen_t errnumlen = sizeof(errnum); 134 | if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errnum, &errnumlen) < 0) 135 | FAIL() << "getsockopt: SO_ERROR"; 136 | if (errnum) { 137 | errno = errnum; 138 | FAIL() << "SO_ERROR"; 139 | } 140 | } 141 | 142 | /* Test sending a datagram to the loopback address port 0. */ 143 | TEST_F(TestUDPv4Send, sendto_loopback_0_so_error) { 144 | int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 145 | if (fd < 0) 146 | FAIL() << "socket"; 147 | struct sockaddr_in sin {}; 148 | memset(&sin, 0, sizeof(sin)); 149 | sin.sin_family = AF_INET; 150 | sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 151 | sin.sin_port = htons(0); 152 | char x = 'x'; 153 | if (sendto(fd, &x, sizeof(x), 0, (const struct sockaddr *)&sin, sizeof(sin)) >= 0) 154 | FAIL() << "sendto"; 155 | usleep(50000); 156 | int errnum; 157 | socklen_t errnumlen = sizeof(errnum); 158 | if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errnum, &errnumlen) < 0) 159 | FAIL() << "getsockopt: SO_ERROR"; 160 | if (errnum) { 161 | errno = errnum; 162 | FAIL() << "SO_ERROR"; 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /test/module-pcap/pcap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | extern "C" { 7 | #include "../../src/environment/network_env.h" 8 | #include "../../modules/module-pcap/pcap-loader.h" 9 | } 10 | 11 | class TestPCAP : public ::testing::Test { 12 | protected: 13 | void SetUp() override { 14 | init_main_library(); 15 | load_pcap_file("config/single_udp_packet.pcap"); 16 | } 17 | }; 18 | 19 | static void check_ip_pktinfo(struct msghdr *my_msghdr, int ifindex, const char *ipi_addr, const char *ipi_spec_dst) { 20 | cmsghdr *cmsg; 21 | bool ip_pktinfo_seen = false; 22 | for (cmsg = CMSG_FIRSTHDR(my_msghdr); cmsg; cmsg = CMSG_NXTHDR(my_msghdr, cmsg)) { 23 | if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { 24 | struct in_pktinfo *pktinfo = ((struct in_pktinfo *)CMSG_DATA(cmsg)); 25 | ASSERT_EQ(pktinfo->ipi_ifindex, ifindex); 26 | ASSERT_STREQ(inet_ntoa(pktinfo->ipi_addr), ipi_addr); 27 | ASSERT_STREQ(inet_ntoa(pktinfo->ipi_spec_dst), ipi_spec_dst); 28 | ip_pktinfo_seen = true; 29 | } 30 | } 31 | ASSERT_TRUE(ip_pktinfo_seen); 32 | } 33 | 34 | TEST_F(TestPCAP, test_recvmsg_udp_single_packet) { 35 | int socket_fd = socket(AF_INET, SOCK_DGRAM, 0); 36 | ASSERT_GT(socket_fd, 0); 37 | struct sockaddr_in bound_addr = {}; 38 | 39 | bound_addr.sin_family = AF_INET; 40 | inet_pton(AF_INET, "127.0.0.1", &bound_addr.sin_addr); 41 | bound_addr.sin_port = htons(5353); 42 | 43 | int ret = bind(socket_fd, (struct sockaddr *)&bound_addr, sizeof(bound_addr)); 44 | ASSERT_EQ(ret, 0); 45 | const int on = 1; 46 | ret = setsockopt(socket_fd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)); 47 | ASSERT_EQ(ret, 0); 48 | int val = -1; 49 | socklen_t val_len = sizeof(int); 50 | ret = getsockopt(socket_fd, IPPROTO_IP, IP_PKTINFO, (void *)&val, &val_len); 51 | ASSERT_EQ(ret, 0); 52 | ASSERT_NE(val, 0); 53 | 54 | struct msghdr my_msghdr = {}; 55 | struct iovec iov = {}; 56 | struct sockaddr_in msg_name_buffer = {}; 57 | iov.iov_base = calloc(1, 2000); 58 | iov.iov_len = 2000; 59 | 60 | my_msghdr.msg_name = &msg_name_buffer; 61 | my_msghdr.msg_namelen = sizeof(struct sockaddr_in); 62 | my_msghdr.msg_control = calloc(1, 1000); 63 | my_msghdr.msg_controllen = 1000; 64 | my_msghdr.msg_iov = &iov; 65 | my_msghdr.msg_iovlen = 1; 66 | 67 | ssize_t bytes_received = recvmsg(socket_fd, &my_msghdr, 0); 68 | ASSERT_EQ(bytes_received, 28); 69 | char message[] = "\x10\x32\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x06\x67\x6f\x6f\x67\x6c\x65\x03\x63\x6f\x6d\x00\x00\x10\x00\x01"; 70 | for (int i = 0; i < sizeof(message); i++) { 71 | ASSERT_EQ(((char *)iov.iov_base)[i], message[i]); 72 | } 73 | ASSERT_STREQ(inet_ntoa(msg_name_buffer.sin_addr), "127.0.0.1"); 74 | check_ip_pktinfo(&my_msghdr, 1, "127.0.0.1", "127.0.0.1"); 75 | } 76 | 77 | TEST_F(TestPCAP, test_recv_udp_all_packets) { 78 | // int socket_fd1 = socket(AF_INET, SOCK_DGRAM, 0); 79 | // int socket_fd2 = socket(AF_INET, SOCK_DGRAM, 0); 80 | // 81 | // ASSERT_GT(socket_fd1, 0); 82 | // ASSERT_GT(socket_fd2, 0); 83 | // 84 | // struct sockaddr_in bound_addr1 = {}; 85 | // struct sockaddr_in bound_addr2 = {}; 86 | // 87 | // bound_addr1.sin_family = AF_INET; 88 | // inet_pton(AF_INET, "127.0.0.1", &bound_addr1.sin_addr); 89 | // bound_addr1.sin_port = htons(5353); 90 | // 91 | // bound_addr2.sin_family = AF_INET; 92 | // inet_pton(AF_INET, "0.0.0.0", &bound_addr2.sin_addr); 93 | // bound_addr2.sin_port = htons(49183); 94 | // int on = 1; 95 | // int ret = setsockopt(socket_fd2, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)); 96 | // ASSERT_EQ(ret, 0); 97 | // 98 | // ret = bind(socket_fd1, (struct sockaddr *) &bound_addr1, sizeof(bound_addr1)); 99 | // ASSERT_EQ(ret, 0); 100 | // ret = bind(socket_fd2, (struct sockaddr *) &bound_addr2, sizeof(bound_addr2)); 101 | // ASSERT_EQ(ret, 0); 102 | // 103 | // struct msghdr my_msghdr = {}; 104 | // struct iovec iov = {}; 105 | // struct sockaddr_in msg_name_buffer = {}; 106 | // iov.iov_base = calloc(1, 2000); 107 | // iov.iov_len = 2000; 108 | // 109 | // my_msghdr.msg_name = &msg_name_buffer; 110 | // my_msghdr.msg_namelen = sizeof(struct sockaddr_in); 111 | // my_msghdr.msg_control = calloc(1, 1000); 112 | // my_msghdr.msg_controllen = 1000; 113 | // my_msghdr.msg_iov = &iov; 114 | // my_msghdr.msg_iovlen = 1; 115 | // 116 | // ssize_t bytes_received = recvmsg(socket_fd1, &my_msghdr, 0); 117 | // ASSERT_EQ(bytes_received, 28); 118 | // bytes_received = recv(socket_fd1, &iov.iov_base, iov.iov_len, 0); 119 | // ASSERT_EQ(bytes_received, 28); 120 | // bytes_received = recv(socket_fd1, &iov.iov_base, 10, 0); 121 | // ASSERT_EQ(bytes_received, 10); 122 | // bytes_received = recv(socket_fd1, &iov.iov_base, iov.iov_len, 0); 123 | // ASSERT_EQ(bytes_received, 43); 124 | // bytes_received = recv(socket_fd1, &iov.iov_base, iov.iov_len, 0); 125 | // ASSERT_EQ(bytes_received, 32); 126 | // bytes_received = recv(socket_fd1, &iov.iov_base, iov.iov_len, 0); 127 | // ASSERT_EQ(bytes_received, 32); 128 | // bytes_received = recv(socket_fd1, &iov.iov_base, iov.iov_len, 0); 129 | // ASSERT_EQ(bytes_received, 29); 130 | // bytes_received = recv(socket_fd1, &iov.iov_base, iov.iov_len, 0); 131 | // ASSERT_EQ(bytes_received, 25); 132 | // bytes_received = recv(socket_fd1, &iov.iov_base, iov.iov_len, 0); 133 | // ASSERT_EQ(bytes_received, 56); 134 | // bytes_received = recv(socket_fd1, &iov.iov_base, iov.iov_len, MSG_DONTWAIT); 135 | // ASSERT_EQ(bytes_received, 0); 136 | // ASSERT_EQ(errno, EAGAIN); 137 | // ASSERT_EXIT(recvfrom(socket_fd1, &iov.iov_base, iov.iov_len, 0, nullptr, nullptr), testing::ExitedWithCode(1), ""); 138 | } -------------------------------------------------------------------------------- /test/environment/rtnetlink/getaddr/rtnetlink_getaddr_filter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | extern "C" { 12 | #include "../../../../include/netfuzzlib/module_api.h" 13 | #include "module.h" 14 | #include "../../../../src/environment/network_env.h" 15 | } 16 | 17 | #define BUFSIZE 8192 18 | 19 | struct nl_req_s { 20 | struct nlmsghdr hdr; 21 | struct rtgenmsg gen; 22 | }; 23 | 24 | class TestRTNetlinkGetaddrFilter : public ::testing::Test { 25 | protected: 26 | void SetUp() override { 27 | init_main_library(); 28 | load_config_file("config/rtnetlink-multiple-interfaces.conf"); 29 | } 30 | }; 31 | 32 | TEST_F(TestRTNetlinkGetaddrFilter, test_getaddr_ipv4) { 33 | struct sockaddr_nl kernel; 34 | int s, end = 0; 35 | ssize_t ret, len; 36 | struct msghdr msg; 37 | struct nl_req_s req; 38 | struct iovec io; 39 | memset(&kernel, 0, sizeof(kernel)); 40 | kernel.nl_family = AF_NETLINK; 41 | kernel.nl_groups = 0; 42 | 43 | //create a Netlink socket 44 | s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 45 | ASSERT_LT(0, s); 46 | 47 | //build netlink message 48 | memset(&req, 0, sizeof(req)); 49 | req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); 50 | req.hdr.nlmsg_type = RTM_GETADDR; 51 | req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 52 | req.hdr.nlmsg_seq = 1; 53 | req.hdr.nlmsg_pid = 1000; 54 | req.gen.rtgen_family = AF_INET; 55 | 56 | memset(&io, 0, sizeof(io)); 57 | io.iov_base = &req; 58 | io.iov_len = req.hdr.nlmsg_len; 59 | 60 | memset(&msg, 0, sizeof(msg)); 61 | msg.msg_iov = &io; 62 | msg.msg_iovlen = 1; 63 | msg.msg_name = &kernel; 64 | msg.msg_namelen = sizeof(kernel); 65 | 66 | //send the message 67 | ret = sendmsg(s, &msg, 0); 68 | ASSERT_EQ(ret, io.iov_len); 69 | 70 | struct sockaddr_nl peername; 71 | socklen_t peername_len = sizeof(struct sockaddr_nl); 72 | 73 | ret = getpeername(s, (struct sockaddr *)&peername, &peername_len); 74 | ASSERT_EQ(ret, 0); 75 | ASSERT_EQ(peername.nl_family, AF_NETLINK); 76 | ASSERT_EQ(peername.nl_groups, 0); 77 | ASSERT_EQ(peername.nl_pid, 0); 78 | char buf[BUFSIZE]; 79 | 80 | int msg_count = 0; 81 | while (!end) { 82 | memset(buf, 0, BUFSIZE); 83 | msg.msg_iov->iov_base = buf; 84 | msg.msg_iov->iov_len = BUFSIZE; 85 | len = recvmsg(s, &msg, MSG_DONTWAIT); 86 | ASSERT_LT(0, len); 87 | 88 | for (struct nlmsghdr *msg_ptr = (struct nlmsghdr *)buf; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) { 89 | msg_count++; 90 | ASSERT_TRUE(msg_ptr->nlmsg_flags & NLM_F_MULTI); 91 | switch (msg_ptr->nlmsg_type) { 92 | case NLMSG_DONE: 93 | end++; 94 | break; 95 | case RTM_NEWADDR: { 96 | struct ifaddrmsg *ifaddr = (struct ifaddrmsg *)NLMSG_DATA(msg_ptr); 97 | ASSERT_EQ(ifaddr->ifa_family, AF_INET); 98 | break; 99 | } 100 | default: 101 | FAIL(); //"Received unknown message type" 102 | } 103 | } 104 | ASSERT_EQ(len, 0); 105 | } 106 | 107 | ASSERT_EQ(msg_count, 6); //5 Addresses + NLMSG_DONE 108 | close(s); 109 | } 110 | 111 | TEST_F(TestRTNetlinkGetaddrFilter, test_getaddr_ipv6) { 112 | struct sockaddr_nl kernel; 113 | int s, end = 0; 114 | ssize_t ret, len; 115 | struct msghdr msg; 116 | struct nl_req_s req; 117 | struct iovec io; 118 | memset(&kernel, 0, sizeof(kernel)); 119 | kernel.nl_family = AF_NETLINK; 120 | kernel.nl_groups = 0; 121 | 122 | //create a Netlink socket 123 | s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 124 | ASSERT_LT(0, s); 125 | 126 | //build netlink message 127 | memset(&req, 0, sizeof(req)); 128 | req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); 129 | req.hdr.nlmsg_type = RTM_GETADDR; 130 | req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 131 | req.hdr.nlmsg_seq = 1; 132 | req.hdr.nlmsg_pid = 1000; 133 | req.gen.rtgen_family = AF_INET6; 134 | 135 | memset(&io, 0, sizeof(io)); 136 | io.iov_base = &req; 137 | io.iov_len = req.hdr.nlmsg_len; 138 | 139 | memset(&msg, 0, sizeof(msg)); 140 | msg.msg_iov = &io; 141 | msg.msg_iovlen = 1; 142 | msg.msg_name = &kernel; 143 | msg.msg_namelen = sizeof(kernel); 144 | 145 | //send the message 146 | ret = sendmsg(s, &msg, 0); 147 | ASSERT_EQ(ret, io.iov_len); 148 | 149 | struct sockaddr_nl peername; 150 | socklen_t peername_len = sizeof(struct sockaddr_nl); 151 | 152 | ret = getpeername(s, (struct sockaddr *)&peername, &peername_len); 153 | ASSERT_EQ(ret, 0); 154 | ASSERT_EQ(peername.nl_family, AF_NETLINK); 155 | ASSERT_EQ(peername.nl_groups, 0); 156 | ASSERT_EQ(peername.nl_pid, 0); 157 | char buf[BUFSIZE]; 158 | 159 | int msg_count = 0; 160 | while (!end) { 161 | memset(buf, 0, BUFSIZE); 162 | msg.msg_iov->iov_base = buf; 163 | msg.msg_iov->iov_len = BUFSIZE; 164 | len = recvmsg(s, &msg, MSG_DONTWAIT); 165 | ASSERT_LT(0, len); 166 | 167 | for (struct nlmsghdr *msg_ptr = (struct nlmsghdr *)buf; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) { 168 | msg_count++; 169 | ASSERT_TRUE(msg_ptr->nlmsg_flags & NLM_F_MULTI); 170 | switch (msg_ptr->nlmsg_type) { 171 | case NLMSG_DONE: 172 | end++; 173 | break; 174 | case RTM_NEWADDR: { 175 | struct ifaddrmsg *ifaddr = (struct ifaddrmsg *)NLMSG_DATA(msg_ptr); 176 | ASSERT_EQ(ifaddr->ifa_family, AF_INET6); 177 | break; 178 | } 179 | default: 180 | FAIL(); //"Received unknown message type" 181 | } 182 | } 183 | ASSERT_EQ(len, 0); 184 | } 185 | nfl_log_debug("len left: %d", len); 186 | 187 | ASSERT_EQ(msg_count, 5); //4 Addresses + NLMSG_DONE 188 | close(s); 189 | } 190 | -------------------------------------------------------------------------------- /src/environment/routing.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "routing.h" 5 | #include "network_env.h" 6 | #include "sockets/sockets_util.h" 7 | #include "interfaces.h" 8 | 9 | int nfl_set_ipv4_default_gateway(const char *gateway_addr_text, unsigned int device_index) { 10 | nfl_l2_iface_t *l2_iface = get_l2_iface_by_index(device_index); 11 | if (!l2_iface) { 12 | nfl_log_warn("Could not find l2_iface with index: %d, not setting ipv4 default gateway", device_index); 13 | return -1; 14 | } 15 | ipv4_default_gateway *ipv4_gateway = calloc(1, sizeof(ipv4_default_gateway)); 16 | if (!ipv4_gateway) { 17 | errno = ENOBUFS; 18 | nfl_log_error("Out of heap space, not setting ipv4 default gateway", device_index); 19 | return -1; 20 | } 21 | int ret = inet_pton(AF_INET, gateway_addr_text, &ipv4_gateway->gateway_addr); 22 | if (ret != 1) { 23 | nfl_log_warn("Could not parse ipv4 address: %s, not setting ipv4 default gateway", gateway_addr_text); 24 | } 25 | 26 | nfl_l3_iface_t *l3_iface; 27 | for (l3_iface = l2_iface->l3_interfaces; l3_iface; l3_iface = l3_iface->next) { 28 | if (l3_iface->addr->s.sa_family != AF_INET) 29 | continue; 30 | 31 | if (ipv4_addr_within_subnet(&l3_iface->addr->s4.sin_addr, &l3_iface->netmask->s4.sin_addr, &ipv4_gateway->gateway_addr)) { 32 | ipv4_gateway->interface = l3_iface; 33 | break; 34 | } 35 | } 36 | if (!ipv4_gateway->interface) { 37 | nfl_log_warn("Default gateway address %s was not within subnet of ipv4 interface of l2_iface %s with index %d, not setting ipv4 default gateway", 38 | gateway_addr_text, l2_iface->name, device_index); 39 | return -1; 40 | } 41 | 42 | if (get_network_env()->ipv4_gateway) { 43 | free(get_network_env()->ipv4_gateway); 44 | } 45 | get_network_env()->ipv4_gateway = ipv4_gateway; 46 | nfl_log_info("Default IPv4 gateway set to %s | l2_iface %s", gateway_addr_text, ipv4_gateway->interface->parent_l2_iface->name); 47 | return 0; 48 | } 49 | 50 | int nfl_set_ipv6_default_gateway(const char *gateway_addr_text, unsigned int device_index) { 51 | nfl_l2_iface_t *l2_iface = get_l2_iface_by_index(device_index); 52 | if (!l2_iface) { 53 | nfl_log_warn("Could not find l2_iface with index: %d, not setting ipv6 default gateway", device_index); 54 | return -1; 55 | } 56 | ipv6_default_gateway *ipv6_gateway = calloc(1, sizeof(ipv6_default_gateway)); 57 | if (!ipv6_gateway) { 58 | errno = ENOBUFS; 59 | nfl_log_error("Out of heap space, not setting ipv6 default gateway", device_index); 60 | return -1; 61 | } 62 | int ret = inet_pton(AF_INET6, gateway_addr_text, &ipv6_gateway->gateway_addr); 63 | if (ret != 1) { 64 | nfl_log_warn("Could not parse ipv6 address: %s, not setting ipv6 default gateway", gateway_addr_text); 65 | } 66 | 67 | nfl_l3_iface_t *l3_iface; 68 | for (l3_iface = l2_iface->l3_interfaces; l3_iface; l3_iface = l3_iface->next) { 69 | if (l3_iface->addr->s.sa_family != AF_INET6) 70 | continue; 71 | if (ipv6_addr_within_subnet(&l3_iface->addr->s6.sin6_addr, l3_iface->prefix, &ipv6_gateway->gateway_addr)) { 72 | ipv6_gateway->interface = l3_iface; 73 | break; 74 | } 75 | } 76 | if (!ipv6_gateway->interface) { 77 | nfl_log_warn("Default gateway address %s was not within subnet of ipv6 interface of l2_iface %s with index %d, not setting ipv4 default gateway", 78 | gateway_addr_text, l2_iface->name, device_index); 79 | return -1; 80 | } 81 | 82 | if (get_network_env()->ipv6_gateway) { 83 | free(get_network_env()->ipv6_gateway); 84 | } 85 | get_network_env()->ipv6_gateway = ipv6_gateway; 86 | nfl_log_info("Default IPv6 gateway set to %s | l2_iface %s", gateway_addr_text, ipv6_gateway->interface->parent_l2_iface->name); 87 | return 0; 88 | } 89 | 90 | /** 91 | * Get the local interface which would be used for sending a packet to a given destination 92 | * @param dest_addr The destination address of the packet 93 | * @return A pointer to the nfl_l3_iface_t which would be used as outgoing interface for the packet, or NULL if no route to dest_addr exists 94 | */ 95 | nfl_l3_iface_t *routing_table_lookup_ipv4(const struct in_addr *dest_addr) { 96 | //First check local subnets, otherwise return default gateway 97 | nfl_l2_iface_t *l2_iface; 98 | nfl_l3_iface_t *l3_iface; 99 | 100 | for (int i = 1; i < MAX_L2_INTERFACES; i++) { 101 | l2_iface = get_l2_iface_by_index(i); 102 | if (!l2_iface) 103 | continue; 104 | for (l3_iface = l2_iface->l3_interfaces; l3_iface; l3_iface = l3_iface->next) { 105 | if (l3_iface->addr->s.sa_family != AF_INET) 106 | continue; 107 | if (ipv4_addr_within_subnet(&l3_iface->addr->s4.sin_addr, &l3_iface->netmask->s4.sin_addr, dest_addr)) { 108 | return l3_iface; 109 | } 110 | } 111 | } 112 | if (get_network_env()->ipv4_gateway) { 113 | return get_network_env()->ipv4_gateway->interface; 114 | } 115 | return NULL; 116 | } 117 | 118 | /** 119 | * Get the local interface which would be used for sending a packet to a given destination 120 | * @param dest_addr The destination address of the packet 121 | * @return A pointer to the nfl_l3_iface_t which would be used as outgoing interface for the packet, or NULL if no route to dest_addr exists 122 | */ 123 | nfl_l3_iface_t *routing_table_lookup_ipv6(const struct in6_addr *dest_addr) { 124 | //First check local subnets, otherwise return default gateway 125 | nfl_l2_iface_t *l2_iface; 126 | nfl_l3_iface_t *l3_iface; 127 | for (int i = 1; i < MAX_L2_INTERFACES; i++) { 128 | l2_iface = get_l2_iface_by_index(i); 129 | if (!l2_iface) 130 | continue; 131 | for (l3_iface = l2_iface->l3_interfaces; l3_iface; l3_iface = l3_iface->next) { 132 | if (l3_iface->addr->s.sa_family != AF_INET6) 133 | continue; 134 | if (ipv6_addr_within_subnet(&l3_iface->addr->s6.sin6_addr, l3_iface->prefix, dest_addr)) { 135 | return l3_iface; 136 | } 137 | } 138 | } 139 | if (get_network_env()->ipv6_gateway) { 140 | return get_network_env()->ipv6_gateway->interface; 141 | } 142 | return NULL; 143 | } 144 | 145 | nfl_l3_iface_t *routing_table_lookup(const nfl_addr_t *dest_addr) { 146 | nfl_l3_iface_t *result; 147 | switch (dest_addr->s.sa_family) { 148 | case AF_INET: { 149 | result = routing_table_lookup_ipv4(&dest_addr->s4.sin_addr); 150 | break; 151 | } 152 | case AF_INET6: { 153 | result = routing_table_lookup_ipv6(&dest_addr->s6.sin6_addr); 154 | break; 155 | } 156 | default: 157 | nfl_exit_log(1, "Invalid address family in routing_table_lookup"); 158 | } 159 | if (!result) { 160 | nfl_log_warn("Routing table lookup failed: could not find device that can reach %s", sockaddr_to_str_static_alloc(dest_addr)); 161 | } 162 | return result; 163 | } 164 | -------------------------------------------------------------------------------- /src/hooks/hooks-poll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "netfuzzlib/api.h" 6 | #include "hooks.h" 7 | #include "native.h" 8 | #include "models.h" 9 | #include "sockets/sockets_util.h" 10 | #include "environment/fd_table.h" 11 | 12 | static int liveness_ctr; 13 | 14 | void liveness_ctr_inc() { 15 | liveness_ctr++; 16 | if (liveness_ctr >= 10) { 17 | nfl_log_fatal("5 subsequent select/poll/... calls without event, exiting..."); 18 | nfl_end_priv(); 19 | } 20 | } 21 | 22 | void liveness_ctr_clear() { 23 | liveness_ctr = 0; 24 | } 25 | 26 | void split_fds_select(int nfds, int *max_fd_syscall, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, fd_set *read_fds_syscall, fd_set *write_fds_syscall, 27 | fd_set *except_fds_syscall) { 28 | FD_ZERO(read_fds_syscall); 29 | FD_ZERO(write_fds_syscall); 30 | FD_ZERO(except_fds_syscall); 31 | bool do_read, do_write, do_except; 32 | bool is_set; 33 | int max_fd = 0; 34 | 35 | for (int i = 0; i < nfds; i++) { 36 | if (is_nfl_sock_fd(i)) 37 | continue; 38 | 39 | do_read = (readfds != NULL) && FD_ISSET(i, readfds); 40 | do_write = (writefds != NULL) && FD_ISSET(i, writefds); 41 | do_except = (exceptfds != NULL) && FD_ISSET(i, exceptfds); 42 | 43 | is_set = false; 44 | if (do_read) { 45 | is_set = true; 46 | FD_SET(i, read_fds_syscall); 47 | FD_CLR(i, readfds); 48 | } 49 | if (do_write) { 50 | is_set = true; 51 | FD_SET(i, write_fds_syscall); 52 | FD_CLR(i, writefds); 53 | } 54 | if (do_except) { 55 | is_set = true; 56 | FD_SET(i, except_fds_syscall); 57 | FD_CLR(i, exceptfds); 58 | } 59 | if (is_set) 60 | max_fd = i + 1; 61 | } 62 | *max_fd_syscall = max_fd; 63 | } 64 | 65 | void merge_fds_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, fd_set *read_fds_syscall, fd_set *write_fds_syscall, 66 | fd_set *except_fds_syscall) { 67 | for (int i = 0; i < nfds; i++) { 68 | if (is_nfl_sock_fd(i)) 69 | continue; 70 | 71 | if (readfds != NULL && FD_ISSET(i, read_fds_syscall)) { 72 | FD_SET(i, readfds); 73 | } 74 | if (writefds != NULL && FD_ISSET(i, write_fds_syscall)) { 75 | FD_SET(i, writefds); 76 | } 77 | if (exceptfds != NULL && FD_ISSET(i, except_fds_syscall)) { 78 | FD_SET(i, exceptfds); 79 | } 80 | } 81 | } 82 | 83 | int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { 84 | assert(nfds <= FD_SETSIZE); 85 | 86 | fd_set read_fds_syscall; 87 | fd_set write_fds_syscall; 88 | fd_set except_fds_syscall; 89 | 90 | int max_fd_syscall = 0; 91 | split_fds_select(nfds, &max_fd_syscall, readfds, writefds, exceptfds, &read_fds_syscall, &write_fds_syscall, &except_fds_syscall); 92 | struct timeval my_timeval = { 0 }; 93 | int ret_syscall = select_native(max_fd_syscall, readfds ? &read_fds_syscall : NULL, writefds ? &write_fds_syscall : NULL, 94 | exceptfds ? &except_fds_syscall : NULL, &my_timeval); 95 | 96 | if (ret_syscall < 0) { 97 | return ret_syscall; 98 | } 99 | my_timeval.tv_sec = 0; 100 | my_timeval.tv_usec = 0; 101 | int ret_model = select_nfl(nfds, readfds, writefds, exceptfds); 102 | if (ret_model < 0) { 103 | return -1; 104 | } 105 | merge_fds_select(nfds, readfds, writefds, exceptfds, &read_fds_syscall, &write_fds_syscall, &except_fds_syscall); 106 | 107 | int ret_total = ret_model + ret_syscall; 108 | 109 | if (ret_total == 0) { 110 | liveness_ctr_inc(); 111 | } else { 112 | liveness_ctr_clear(); 113 | } 114 | return ret_total; 115 | } 116 | 117 | int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask) { 118 | struct timeval my_timeval; 119 | my_timeval.tv_sec = timeout->tv_sec; 120 | my_timeval.tv_usec = timeout->tv_nsec / 1000; 121 | 122 | sigset_t origmask; 123 | pthread_sigmask(SIG_SETMASK, sigmask, &origmask); 124 | int ready = select(nfds, readfds, writefds, exceptfds, &my_timeval); 125 | pthread_sigmask(SIG_SETMASK, &origmask, NULL); 126 | return ready; 127 | } 128 | 129 | int poll(struct pollfd *fds, nfds_t nfds, int timeout) { 130 | if (nfds == 0) 131 | return 0; 132 | 133 | struct pollfd *fds_syscall = calloc(sizeof(struct pollfd), nfds); 134 | struct pollfd *fds_model = calloc(sizeof(struct pollfd), nfds); 135 | if (!fds_syscall || !fds_model) { 136 | if (fds_syscall) 137 | free(fds_syscall); 138 | errno = ENOBUFS; 139 | return -1; 140 | } 141 | int i_fds_syscall = 0; 142 | int i_fds_model = 0; 143 | 144 | // Split fds into modelled and native fds 145 | for (int i_fds = 0; i_fds < nfds; i_fds++) { 146 | struct pollfd *current_poll_struct = &fds[i_fds]; 147 | current_poll_struct->revents = 0; 148 | 149 | if (is_nfl_sock_fd(current_poll_struct->fd)) { 150 | nfl_log_debug("Modelled (p)poll call for fd: %s", sock_to_str(get_nfl_sock(fds[i_fds].fd))); 151 | fds_model[i_fds_model].fd = current_poll_struct->fd; 152 | fds_model[i_fds_model].events = current_poll_struct->events; 153 | i_fds_model++; 154 | } else { 155 | nfl_log_debug("Native (p)poll call for fd: %d", fds[i_fds].fd); 156 | fds_syscall[i_fds_syscall].fd = current_poll_struct->fd; 157 | fds_syscall[i_fds_syscall].events = current_poll_struct->events; 158 | i_fds_syscall++; 159 | } 160 | } 161 | int ret_native = poll_native(fds_syscall, i_fds_syscall, 0); 162 | if (ret_native == -1) { 163 | free(fds_syscall); 164 | free(fds_model); 165 | return -1; 166 | } 167 | int ret_model = poll_nfl(fds_model, i_fds_model, 0); 168 | if (ret_model == -1) { 169 | free(fds_syscall); 170 | free(fds_model); 171 | return -1; 172 | } 173 | int ret_total = ret_native + ret_model; 174 | if (ret_total) { 175 | i_fds_syscall = 0; 176 | i_fds_model = 0; 177 | for (int i_fds = 0; i_fds < nfds; i_fds++) { 178 | fds[i_fds].revents = 0; 179 | if (is_nfl_sock_fd(fds[i_fds].fd)) { 180 | fds[i_fds].revents = fds_model[i_fds_model].revents; 181 | i_fds_model++; 182 | } else { 183 | fds[i_fds].revents = fds_syscall[i_fds_syscall].revents; 184 | i_fds_syscall++; 185 | } 186 | } 187 | } 188 | 189 | free(fds_syscall); 190 | free(fds_model); 191 | 192 | if (ret_total == 0) { 193 | liveness_ctr_inc(); 194 | } else { 195 | liveness_ctr_clear(); 196 | } 197 | 198 | return ret_total; 199 | } 200 | 201 | int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask) { 202 | sigset_t origmask; 203 | 204 | int timeout = (timeout_ts == NULL) ? -1 : (int)(timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000); 205 | sigprocmask(SIG_SETMASK, sigmask, &origmask); 206 | int ready = poll(fds, nfds, timeout); 207 | sigprocmask(SIG_SETMASK, &origmask, NULL); 208 | return ready; 209 | } -------------------------------------------------------------------------------- /src/sockets/sockets_dgram.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "sockets_util.h" 3 | #include "sockets.h" 4 | #include "hooks/models.h" 5 | #include "hooks/hooks.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // Set the 'default' remote address of a DGRAM sock 14 | int connect_dgram(nfl_sock_t *sock, const nfl_addr_t *addr, socklen_t addrlen) { 15 | if (addr == NULL || addr->s.sa_family == AF_UNSPEC) { //Calling connect with addr NULL and addrlen 0 should remove the default address 16 | if (addr && addrlen == 0) { //If addr is NULL, then addrlen must be 0 17 | errno = EINVAL; 18 | return -1; 19 | } else { 20 | if (sock->remote_addr) { 21 | free(sock->remote_addr); 22 | sock->remote_addr = NULL; 23 | } 24 | return 0; 25 | } 26 | } 27 | assert(addr->s.sa_family == sock->domain); //Already checked earlier in connect() function 28 | 29 | socklen_t correct_addrlen = get_socket_domain_addrlen(sock->domain); 30 | 31 | if (addrlen != correct_addrlen) { 32 | nfl_log_warn("Connect called on dgram sock with invalid addrlen"); 33 | errno = EINVAL; 34 | return -1; 35 | } 36 | 37 | nfl_addr_t *remote_addr = malloc(sizeof(nfl_addr_t)); 38 | if (!remote_addr) { 39 | errno = ENOMEM; 40 | return -1; 41 | } 42 | memcpy(remote_addr, addr, correct_addrlen); 43 | if (sock->remote_addr != NULL) { 44 | free(sock->remote_addr); 45 | } 46 | sock->remote_addr = remote_addr; 47 | 48 | if (!sock->local_addr) { 49 | if (autobind_udp(sock, addr) == -1) { 50 | free(sock->remote_addr); 51 | sock->remote_addr = NULL; 52 | return -1; 53 | } 54 | } 55 | nfl_log_info("connect() success: %s", sock_to_str(sock)); 56 | return 0; 57 | } 58 | 59 | static void handle_recmvsg_pktinfo(struct msghdr *msg, unsigned int device_index, nfl_addr_t *dest_address_packet_header, nfl_addr_t *device_addr) { 60 | size_t cmsg_len_max = msg->msg_controllen; 61 | size_t cmsg_len_used = 0; 62 | struct cmsghdr *my_cmsghdr = CMSG_FIRSTHDR(msg); 63 | //See RFC 3542 64 | if (!my_cmsghdr) { 65 | nfl_log_warn("IP_PKTINFO or IPV6_PKTINFO asked, passed buffer to small, returning flag MSG_CTRUNC \n"); 66 | msg->msg_flags |= MSG_CTRUNC; 67 | } else { 68 | if (dest_address_packet_header->s.sa_family == AF_INET6) { 69 | if (cmsg_len_used + CMSG_SPACE(sizeof(struct in6_pktinfo)) > cmsg_len_max) { 70 | nfl_log_warn("IPV6_PKTINFO asked, passed buffer to small, returning flag MSG_CTRUNC \n"); 71 | msg->msg_flags |= MSG_CTRUNC; 72 | } else { 73 | my_cmsghdr->cmsg_level = IPPROTO_IPV6; 74 | my_cmsghdr->cmsg_type = IPV6_PKTINFO; 75 | my_cmsghdr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 76 | struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)CMSG_DATA(my_cmsghdr); 77 | pktinfo->ipi6_ifindex = device_index; 78 | memcpy(&pktinfo->ipi6_addr, &((struct sockaddr_in6 *)dest_address_packet_header)->sin6_addr, sizeof(struct in6_addr)); 79 | cmsg_len_used += CMSG_SPACE(sizeof(struct in6_pktinfo)); 80 | msg->msg_controllen = cmsg_len_used; 81 | } 82 | } else if (dest_address_packet_header->s.sa_family == AF_INET) { 83 | if (cmsg_len_used + CMSG_SPACE(sizeof(struct in_pktinfo)) > cmsg_len_max) { 84 | nfl_log_warn("IP_PKTINFO asked, passed buffer to small, returning flag MSG_CTRUNC \n"); 85 | msg->msg_flags |= MSG_CTRUNC; 86 | } else { 87 | my_cmsghdr->cmsg_level = IPPROTO_IP; 88 | my_cmsghdr->cmsg_type = IP_PKTINFO; 89 | my_cmsghdr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); 90 | struct in_pktinfo *pktinfo = (struct in_pktinfo *)CMSG_DATA(my_cmsghdr); 91 | pktinfo->ipi_ifindex = (int)device_index; 92 | pktinfo->ipi_addr.s_addr = ((struct sockaddr_in *)dest_address_packet_header)->sin_addr.s_addr; 93 | pktinfo->ipi_spec_dst.s_addr = ((struct sockaddr_in *)device_addr)->sin_addr.s_addr; 94 | cmsg_len_used += CMSG_SPACE(sizeof(struct in_pktinfo)); 95 | msg->msg_controllen = cmsg_len_used; 96 | } 97 | } 98 | } 99 | } 100 | 101 | ssize_t recvmsg_dgram(nfl_sock_t *sock, struct msghdr *msg, int flags) { 102 | if (!sock->local_addr) { 103 | errno = ENOTCONN; 104 | return -1; 105 | } 106 | 107 | sock_update_recv_buffer(sock); 108 | 109 | if (!sock->packets_ll) { 110 | if (!sock->status_flags.blocking || IS_FLAG_SET(flags, MSG_DONTWAIT)) { 111 | errno = EAGAIN; 112 | return 0; 113 | } else { 114 | nfl_log_fatal("Blocking recv(/from/msg) on sock without incoming data, %s", sock_to_str(sock)); 115 | nfl_end_priv(); 116 | } 117 | } 118 | 119 | if (sock->status_flags.recv_pkt_info) { 120 | handle_recmvsg_pktinfo(msg, sock->packets_ll->device_index, &sock->packets_ll->local_addr, sock->local_addr); 121 | } 122 | 123 | socklen_t correct_addrlen = get_socket_domain_addrlen(sock->domain); 124 | if (msg->msg_name) { 125 | if (msg->msg_namelen < correct_addrlen) { 126 | nfl_log_warn("recv{from/msg} call with passed sockaddr length too short"); 127 | memcpy(msg->msg_name, &sock->packets_ll->remote_addr, msg->msg_namelen); 128 | } else { 129 | memcpy(msg->msg_name, &sock->packets_ll->remote_addr, correct_addrlen); 130 | } 131 | msg->msg_namelen = correct_addrlen; 132 | } 133 | 134 | ssize_t amount_bytes_available = (ssize_t)sock_recv_buffer_bytes_available(sock); 135 | ssize_t amount_bytes_read = socket_recv_iov(sock, msg->msg_iov, msg->msg_iovlen, IS_FLAG_SET(flags, MSG_PEEK)); 136 | if (amount_bytes_available != amount_bytes_read) { 137 | msg->msg_flags |= MSG_TRUNC; 138 | if (!IS_FLAG_SET(flags, MSG_PEEK)) { 139 | sock_clear_recv_buffer_and_load_next_packet(sock); 140 | } 141 | } 142 | 143 | if (IS_FLAG_SET(flags, MSG_TRUNC)) { 144 | return amount_bytes_available; 145 | } 146 | return amount_bytes_read; 147 | } 148 | 149 | ssize_t sendmsg_dgram(nfl_sock_t *sock, const struct msghdr *msg, int flags) { 150 | nfl_addr_t receiver; 151 | if (msg->msg_name && msg->msg_namelen) { 152 | if (msg->msg_namelen < get_socket_domain_addrlen(sock->domain)) { 153 | errno = EINVAL; 154 | return -1; 155 | } 156 | memcpy(&receiver, msg->msg_name, msg->msg_namelen); 157 | } else if (sock->remote_addr) { 158 | memcpy(&receiver, &sock->remote_addr, sizeof(nfl_addr_t)); 159 | } else { 160 | errno = EDESTADDRREQ; 161 | return -1; 162 | } 163 | 164 | if (!sock->local_addr) { 165 | int ret = autobind_udp(sock, &receiver); 166 | if (ret < 0) { 167 | nfl_log_error("Could not send data on %s to %s", sock_to_str(sock), sockaddr_to_str_static_alloc(&receiver)); 168 | return -1; 169 | } 170 | } 171 | ssize_t amount_bytes_sent = nfl_send((const nfl_sock_module_t *)sock, sock->local_addr, &receiver, msg->msg_iov, msg->msg_iovlen); 172 | 173 | #ifdef NFL_DEBUG 174 | char sender_str[SOCKADDR_STR_MAX_LEN], receiver_str[SOCKADDR_STR_MAX_LEN]; 175 | sockaddr_to_str(sock->local_addr, sender_str, sizeof(sender_str)); 176 | sockaddr_to_str(&receiver, receiver_str, sizeof(receiver_str)); 177 | nfl_log_info("Sent %d bytes | from: %s | to %s | %s", amount_bytes_sent, sender_str, receiver_str, sock_to_str(sock)); 178 | #endif 179 | return amount_bytes_sent; 180 | } -------------------------------------------------------------------------------- /src/environment/ioctl.c: -------------------------------------------------------------------------------- 1 | #include "hooks/hooks.h" 2 | #include "sockets/sockets_util.h" 3 | #include "interfaces.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define IOCTL_CASE(request, msg, ret) \ 11 | case ((request)): \ 12 | nfl_log_warn("ioctl: " msg); \ 13 | return (ret); \ 14 | break 15 | 16 | /** 17 | * Handle a SIOCGIFCONF ioctl request 18 | * @param my_ifconf The ifconf struct to fill 19 | * @return 0 on success, -1 on error 20 | */ 21 | static int handle_siocgifconf(struct ifconf *my_ifconf) { 22 | int l3_ipv4_ifaces_count = get_l3_iface_ipv4_count(); // Only returns IPV4 l3_interfaces 23 | int ifc_len_required = (int)sizeof(struct ifreq) * l3_ipv4_ifaces_count; 24 | 25 | if (my_ifconf->ifc_req == NULL) { 26 | my_ifconf->ifc_len = ifc_len_required; 27 | return 0; 28 | } 29 | if (ifc_len_required > my_ifconf->ifc_len) { 30 | l3_ipv4_ifaces_count = my_ifconf->ifc_len / ((int)sizeof(struct ifreq)); 31 | } 32 | 33 | my_ifconf->ifc_len = l3_ipv4_ifaces_count * ((int)sizeof(struct ifreq)); 34 | 35 | nfl_l2_iface_t *iface_l2; 36 | nfl_l3_iface_t *iface_l3; 37 | 38 | int count = 0; 39 | 40 | for (int i = 1; i < MAX_L2_INTERFACES; i++) { 41 | iface_l2 = get_l2_iface_by_index(i); 42 | if (!iface_l2) 43 | continue; 44 | for (iface_l3 = iface_l2->l3_interfaces; iface_l3; iface_l3 = iface_l3->next) { 45 | if (iface_l3->addr->s.sa_family != AF_INET) 46 | continue; 47 | strcpy(my_ifconf->ifc_req[count].ifr_name, iface_l2->name); 48 | memcpy(&my_ifconf->ifc_req[count].ifr_addr, iface_l3->addr, sizeof(struct sockaddr_in)); 49 | count++; 50 | if (count >= l3_ipv4_ifaces_count) { 51 | break; 52 | } 53 | } 54 | } 55 | return 0; 56 | } 57 | 58 | /* 59 | * See man 7 netdevice 60 | */ 61 | int ioctl_nfl(nfl_sock_t *sock, unsigned long request, void *argp) { 62 | if (!argp) 63 | return -EINVAL; 64 | switch (request) { 65 | case SIOCGIFCONF: 66 | return handle_siocgifconf((struct ifconf *)argp); 67 | case FIONREAD: 68 | *((int *)argp) = (int)sock_recv_buffer_bytes_available(sock); 69 | return 0; 70 | case FIONBIO: { 71 | int *non_blocking = (int *)argp; 72 | sock->status_flags.blocking = !(*non_blocking); 73 | return 0; 74 | } 75 | case FIOCLEX: 76 | case FIONCLEX: 77 | return 0; 78 | } 79 | 80 | struct ifreq *my_ifreq = (struct ifreq *)argp; 81 | 82 | nfl_l2_iface_t *l2_iface = request == SIOCGIFNAME ? get_l2_iface_by_index(my_ifreq->ifr_ifindex) : get_l2_iface_by_name(my_ifreq->ifr_name); 83 | 84 | if (!l2_iface) { 85 | return -EINVAL; 86 | } 87 | 88 | switch (request) { 89 | case SIOCGIFNAME: // get l2_iface name 90 | strcpy(my_ifreq->ifr_name, l2_iface->name); 91 | return 0; 92 | case SIOCGIFINDEX: // get l2_iface index 93 | my_ifreq->ifr_ifindex = (int)l2_iface->index; 94 | return 0; 95 | case SIOCGIFFLAGS: // get flags 96 | my_ifreq->ifr_flags = l2_iface->flags; 97 | return 0; 98 | case SIOCGIFPFLAGS: 99 | my_ifreq->ifr_flags = 0; 100 | return 0; 101 | case SIOCGIFADDR: { // ipv4 only! 102 | nfl_l3_iface_t *l3_iface = l2_iface->l3_interfaces; 103 | while (l3_iface) { 104 | if (l3_iface->addr->s.sa_family == AF_INET) { 105 | memcpy(&my_ifreq->ifr_addr, l3_iface->addr, sizeof(struct sockaddr_in)); 106 | return 0; 107 | } 108 | l3_iface = l3_iface->next; 109 | } 110 | return -EINVAL; 111 | } 112 | case SIOCGIFHWADDR: 113 | memset(&my_ifreq->ifr_hwaddr, 0, sizeof(struct sockaddr)); 114 | my_ifreq->ifr_hwaddr.sa_family = IS_FLAG_SET(l2_iface->flags, IFF_LOOPBACK) ? ARPHRD_LOOPBACK : ARPHRD_ETHER; 115 | memcpy(my_ifreq->ifr_hwaddr.sa_data, l2_iface->hw_addr, ETHER_ADDR_LEN); 116 | return 0; 117 | 118 | case SIOCGIFBRDADDR: { 119 | nfl_l3_iface_t *l3_iface = l2_iface->l3_interfaces; 120 | while (l3_iface) { 121 | if (l3_iface->addr->s.sa_family == AF_INET) { 122 | get_l3_iface_broadcast_addr(l3_iface, (struct sockaddr_in *)&my_ifreq->ifr_broadaddr); 123 | return 0; 124 | } 125 | l3_iface = l3_iface->next; 126 | } 127 | return -EINVAL; 128 | } 129 | 130 | case SIOCGIFNETMASK: { 131 | nfl_l3_iface_t *l3_iface = l2_iface->l3_interfaces; 132 | while (l3_iface) { 133 | if (l3_iface->addr->s.sa_family == AF_INET) { 134 | memcpy(&my_ifreq->ifr_netmask, l3_iface->netmask, sizeof(struct sockaddr_in)); 135 | return 0; 136 | } 137 | l3_iface = l3_iface->next; 138 | } 139 | return -EINVAL; 140 | } 141 | case SIOCGIFMTU: 142 | my_ifreq->ifr_mtu = l2_iface->mtu; 143 | return 0; 144 | case SIOCGIFTXQLEN: 145 | my_ifreq->ifr_qlen = 1000; 146 | return 0; 147 | case SIOCGIFMAP: 148 | nfl_log_warn("Ioctl requesting getting l2_iface hardware params (SIOCGIFMAP), return dummy value"); 149 | memset(&my_ifreq->ifr_map, 0, sizeof(struct ifmap)); 150 | return 0; 151 | case SIOCGIFMETRIC: 152 | nfl_log_warn("Ioctl requesting getting l2_iface metric (SIOCGIFMETRIC), silent ignore, return 0 as metric, same behaviour as glibc"); 153 | my_ifreq->ifr_metric = 0; 154 | return 0; 155 | case SIOCSIFMETRIC: 156 | nfl_log_warn("Ioctl requesting setting l2_iface metric (SIOCSIFMETRIC), return EOPNOTSUPP, same behaviour as glibc"); 157 | return -EOPNOTSUPP; //Same as glibc behaviour 158 | IOCTL_CASE(SIOCSIFFLAGS, "requesting setting l2_iface flags (SIOCSIFFLAGS), returning no permissions (EPERM)", -EPERM); 159 | IOCTL_CASE(SIOCSIFPFLAGS, "requesting setting extended network l2_iface flags (SIOCSIFPFLAGS), returning no permissions (EPERM)", -EPERM); 160 | IOCTL_CASE(SIOCSIFADDR, "requesting setting l2_iface ipv4/v6 address (SIOCSIFADDR), returning no permissions (EPERM)", -EPERM); 161 | IOCTL_CASE(SIOCDIFADDR, "requesting deleting l2_iface ipv6 address (SIOCDIFADDR), returning no permissions (EPERM)", -EPERM); 162 | IOCTL_CASE(SIOCGIFDSTADDR, "requesting action on point to point l2_iface (SIOCGIFDSTADDR), returning operation not supported (EOPNOTSUPP)", 163 | -EOPNOTSUPP); 164 | IOCTL_CASE(SIOCSIFDSTADDR, "requesting action on point to point l2_iface (SIOCGIFDSTADDR), returning no permissions (EPERM)", -EPERM); 165 | IOCTL_CASE(SIOCSIFHWADDR, "requesting setting l2_iface hardware address (SIOCSIFHWADDR), returning no permissions (EPERM)", -EPERM); 166 | IOCTL_CASE(SIOCSIFBRDADDR, "requesting setting l2_iface ipv4 broadcast address (SIOCSIFBRDADDR), returning no permissions (EPERM)", -EPERM); 167 | IOCTL_CASE(SIOCSIFNETMASK, "requesting setting l2_iface netmask (SIOCSIFNETMASK), returning no permissions (EPERM)", -EPERM); 168 | IOCTL_CASE(SIOCSIFMTU, "requesting setting l2_iface mtu (SIOCSIFMTU), returning no permissions (EPERM)", -EPERM); 169 | IOCTL_CASE(SIOCSIFHWBROADCAST, "requesting setting hardware broadcast address (SIOCSIFHWBROADCAST), returning no permissions (EPERM)", -EPERM); 170 | IOCTL_CASE(SIOCSIFMAP, "requesting setting l2_iface hardware params (SIOCSIFMAP), returning no permissions (EPERM)", -EPERM); 171 | IOCTL_CASE(SIOCADDMULTI, "requesting adding link layer multicast filter address from l2_iface (SIOCADDMULTI), returning no permissions (EPERM)", 172 | -EPERM); 173 | IOCTL_CASE(SIOCDELMULTI, "requesting deleting link layer multicast filter address from l2_iface (SIOCDELMULTI), returning no permissions (EPERM)", 174 | -EPERM); 175 | IOCTL_CASE(SIOCSIFTXQLEN, "requesting setting transmit queue length to l2_iface (SIOCGIFTXQLEN), returning no permissions (EPERM)", -EPERM); 176 | IOCTL_CASE(SIOCSIFNAME, "requesting changing l2_iface name (SIOCSIFNAME), returning no permissions (EPERM)", -EPERM); 177 | default: 178 | return -EINVAL; 179 | } 180 | } --------------------------------------------------------------------------------