diff --git a/src/test/unit/unit.c b/src/test/unit/unit.c index cc95d33..a11b142 100644 --- a/src/test/unit/unit.c +++ b/src/test/unit/unit.c @@ -147,6 +147,7 @@ Suite *wolf_suite(void) tcase_add_test(tc_utils, test_filter_setters_and_get_mask); tcase_add_test(tc_utils, test_sock_socket_errors); tcase_add_test(tc_utils, test_regression_sock_socket_null_wolfip_returns_einval); + tcase_add_test(tc_utils, test_regression_sock_entrypoints_null_wolfip_returns_einval); tcase_add_test(tc_utils, test_sock_socket_udp_protocol_zero); tcase_add_test(tc_utils, test_sock_socket_full_tables); tcase_add_test(tc_utils, test_filter_mask_for_proto_variants); @@ -256,6 +257,7 @@ Suite *wolf_suite(void) tcase_add_test(tc_utils, test_established_fin_without_ack_dropped); tcase_add_test(tc_utils, test_ip_recv_drops_source_routed_packet); tcase_add_test(tc_utils, test_ip_recv_drops_ssrr_source_routed_packet); + tcase_add_test(tc_utils, test_ip_recv_drops_source_routed_packet_overlong_first_option_hides_lsrr); tcase_add_test(tc_utils, test_sock_sendto_error_paths); tcase_add_test(tc_utils, test_sock_sendto_null_buf_or_len_zero); tcase_add_test(tc_utils, test_sock_sendto_tcp_not_established); @@ -637,6 +639,8 @@ Suite *wolf_suite(void) tcase_add_test(tc_utils, test_udp_checksum_valid_passes); tcase_add_test(tc_utils, test_udp_checksum_invalid_rejected); tcase_add_test(tc_utils, test_udp_checksum_zero_accepted); + tcase_add_test(tc_utils, test_regression_udp_recv_sets_last_pkt_ttl); + tcase_add_test(tc_utils, test_regression_tcp_input_sets_last_pkt_ttl); tcase_add_test(tc_utils, test_udp_connected_rejects_wrong_source_ip); tcase_add_test(tc_utils, test_ip_checksum_invalid_rejected); tcase_add_test(tc_utils, test_ip_checksum_valid_passes); @@ -734,6 +738,7 @@ Suite *wolf_suite(void) tcase_add_test(tc_proto, test_raw_socket_recv_captures_ip_header); tcase_add_test(tc_proto, test_raw_socket_send_hdrincl_respected); tcase_add_test(tc_proto, test_raw_socket_send_builds_ip_header); + tcase_add_test(tc_proto, test_regression_raw_socket_send_ip_id_network_byte_order); tcase_add_test(tc_proto, test_raw_socket_sendto_short_addrlen_returns_einval); tcase_add_test(tc_proto, test_raw_socket_sendto_wrong_family_returns_einval); tcase_add_test(tc_proto, test_raw_socket_sendto_payload_too_large_for_ip_header_returns_einval); @@ -784,6 +789,7 @@ Suite *wolf_suite(void) tcase_add_test(tc_proto, test_ip_recv_forward_ttl_exceeded); tcase_add_test(tc_proto, test_ip_recv_udp_with_ip_options_delivers_payload); tcase_add_test(tc_proto, test_ip_recv_fragmented_udp_dropped); + tcase_add_test(tc_proto, test_ip_recv_fragmented_udp_dropped_offset_only); tcase_add_test(tc_proto, test_ip_recv_forward_arp_queue_and_flush); tcase_add_test(tc_proto, test_arp_flush_pending_ttl_expired); tcase_add_test(tc_proto, test_wolfip_forwarding_basic); @@ -792,6 +798,7 @@ Suite *wolf_suite(void) tcase_add_test(tc_proto, test_forward_packet_eth_filter_drop); tcase_add_test(tc_proto, test_loopback_dest_not_forwarded); tcase_add_test(tc_proto, test_regression_forwarding_rpf_drops_spoofed_source); + tcase_add_test(tc_proto, test_regression_forwarding_drops_source_routed_packet); tcase_add_test(tc_proto, test_regression_loopback_source_dropped_on_non_loopback_iface); tcase_add_test(tc_proto, test_regression_icmp_echo_request_non_local_dst_no_reply); tcase_add_test(tc_proto, test_tcp_listen_rejects_wrong_interface); diff --git a/src/test/unit/unit_tests_api.c b/src/test/unit/unit_tests_api.c index 3ae1bb1..175ed3a 100644 --- a/src/test/unit/unit_tests_api.c +++ b/src/test/unit/unit_tests_api.c @@ -482,6 +482,48 @@ START_TEST(test_regression_sock_socket_null_wolfip_returns_einval) -WOLFIP_EINVAL); } END_TEST + +START_TEST(test_regression_sock_entrypoints_null_wolfip_returns_einval) +{ + int tcp_fd = (int)MARK_TCP_SOCKET; + struct wolfIP_sockaddr_in sin; + socklen_t slen = (socklen_t)sizeof(sin); + uint8_t buf[1] = { 0 }; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = ee16(1234); + sin.sin_addr.s_addr = 0; /* IPADDR_ANY, keeps bind on the deref path */ + + ck_assert_int_eq( + wolfIP_sock_connect(NULL, tcp_fd, (struct wolfIP_sockaddr *)&sin, slen), + -WOLFIP_EINVAL); + ck_assert_int_eq( + wolfIP_sock_accept(NULL, tcp_fd, NULL, NULL), + -WOLFIP_EINVAL); + ck_assert_int_eq( + wolfIP_sock_sendto(NULL, tcp_fd, buf, sizeof(buf), 0, NULL, 0), + -WOLFIP_EINVAL); + ck_assert_int_eq( + wolfIP_sock_recvfrom(NULL, tcp_fd, buf, sizeof(buf), 0, NULL, NULL), + -WOLFIP_EINVAL); + ck_assert_int_eq( + wolfIP_sock_close(NULL, tcp_fd), + -WOLFIP_EINVAL); + ck_assert_int_eq( + wolfIP_sock_getsockname(NULL, tcp_fd, (struct wolfIP_sockaddr *)&sin, &slen), + -WOLFIP_EINVAL); + ck_assert_int_eq( + wolfIP_sock_bind(NULL, tcp_fd, (struct wolfIP_sockaddr *)&sin, slen), + -WOLFIP_EINVAL); + ck_assert_int_eq( + wolfIP_sock_listen(NULL, tcp_fd, 0), + -WOLFIP_EINVAL); + ck_assert_int_eq( + wolfIP_sock_getpeername(NULL, tcp_fd, (struct wolfIP_sockaddr *)&sin, &slen), + -WOLFIP_EINVAL); +} +END_TEST START_TEST(test_udp_sendto_and_recvfrom) { struct wolfIP s; @@ -4773,3 +4815,85 @@ START_TEST(test_ip_recv_drops_ssrr_source_routed_packet) ck_assert_int_eq(listener->sock.tcp.state, TCP_LISTEN); } END_TEST + +START_TEST(test_ip_recv_drops_source_routed_packet_overlong_first_option_hides_lsrr) +{ + struct wolfIP s; + int listen_sd; + struct tsocket *listener; + struct wolfIP_sockaddr_in sin; + uint8_t pkt[ETH_HEADER_LEN + 24 + TCP_HEADER_LEN]; + struct wolfIP_ip_packet *ip; + struct wolfIP_ll_dev *ll; + union transport_pseudo_header ph; + uint16_t *tcp_csum_field; + static const uint8_t src_mac[6] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60}; + + wolfIP_init(&s); + mock_link_init(&s); + wolfIP_ipconfig_set(&s, 0x0A000001U, 0xFFFFFF00U, 0); + + listen_sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_STREAM, WI_IPPROTO_TCP); + ck_assert_int_gt(listen_sd, 0); + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = ee16(1234); + sin.sin_addr.s_addr = ee32(0x0A000001U); + ck_assert_int_eq(wolfIP_sock_bind(&s, listen_sd, (struct wolfIP_sockaddr *)&sin, sizeof(sin)), 0); + ck_assert_int_eq(wolfIP_sock_listen(&s, listen_sd, 1), 0); + listener = &s.tcpsockets[SOCKET_UNMARK(listen_sd)]; + + ll = wolfIP_getdev_ex(&s, TEST_PRIMARY_IF); + memset(pkt, 0, sizeof(pkt)); + + ip = (struct wolfIP_ip_packet *)pkt; + memcpy(ip->eth.dst, ll->mac, 6); + memcpy(ip->eth.src, src_mac, 6); + ip->eth.type = ee16(ETH_TYPE_IP); + + /* IHL=6 to 4 bytes of IP options. */ + ip->ver_ihl = 0x46; + ip->ttl = 64; + ip->proto = WI_IPPROTO_TCP; + ip->len = ee16(24 + TCP_HEADER_LEN); + ip->src = ee32(0x0A0000A1U); + ip->dst = ee32(0x0A000001U); + + { + uint8_t *opts = pkt + ETH_HEADER_LEN + IP_HEADER_LEN; + opts[0] = 0x07; /* Record Route */ + opts[1] = 5; /* overlong: greater than remaining 4-byte budget */ + opts[2] = 0x83; /* LSRR hidden inside the apparent RR payload */ + opts[3] = 0x00; /* End of Options */ + } + ip->csum = 0; + iphdr_set_checksum(ip); + + { + uint8_t *tcp = pkt + ETH_HEADER_LEN + 24; + tcp[0] = (uint8_t)(40000 >> 8); + tcp[1] = (uint8_t)(40000 & 0xFF); + tcp[2] = (uint8_t)(1234 >> 8); + tcp[3] = (uint8_t)(1234 & 0xFF); + tcp[4] = 0; tcp[5] = 0; tcp[6] = 0; tcp[7] = 1; + tcp[12] = TCP_HEADER_LEN << 2; + tcp[13] = TCP_FLAG_SYN; + tcp[14] = 0xFF; tcp[15] = 0xFF; + tcp_csum_field = (uint16_t *)(tcp + 16); + *tcp_csum_field = 0; + memset(&ph, 0, sizeof(ph)); + ph.ph.src = ip->src; + ph.ph.dst = ip->dst; + ph.ph.proto = WI_IPPROTO_TCP; + ph.ph.len = ee16(TCP_HEADER_LEN); + *tcp_csum_field = ee16(transport_checksum(&ph, tcp)); + } + + ip_recv(&s, TEST_PRIMARY_IF, ip, sizeof(pkt)); + + /* Listener must stay in LISTEN: the hidden LSRR must be detected so the + * packet is dropped before tcp_input is invoked. With the buggy parser + * the SYN reaches the listener and flips it to TCP_SYN_RCVD. */ + ck_assert_int_eq(listener->sock.tcp.state, TCP_LISTEN); +} +END_TEST diff --git a/src/test/unit/unit_tests_proto.c b/src/test/unit/unit_tests_proto.c index 9cb38c5..f64a027 100644 --- a/src/test/unit/unit_tests_proto.c +++ b/src/test/unit/unit_tests_proto.c @@ -3816,6 +3816,58 @@ START_TEST(test_regression_forwarding_rpf_drops_spoofed_source) } END_TEST +START_TEST(test_regression_forwarding_drops_source_routed_packet) +{ + static const uint8_t opt_types[] = { 0x83U, 0x89U }; /* LSRR, SSRR */ + static const uint8_t src_mac[6] = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56}; + static const uint8_t iface1_mac[6] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x02}; + static const uint8_t next_hop_mac[6] = {0x02, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE}; + static const uint32_t dest_ip = 0xC0A80164U; /* 192.168.1.100 on TEST_SECOND_IF */ + unsigned int i; + + for (i = 0; i < sizeof(opt_types) / sizeof(opt_types[0]); i++) { + struct wolfIP s; + uint8_t frame_buf[ETH_HEADER_LEN + IP_HEADER_LEN + 4]; + struct wolfIP_ip_packet *frame = (struct wolfIP_ip_packet *)frame_buf; + uint8_t *opts = frame_buf + ETH_HEADER_LEN + IP_HEADER_LEN; + + wolfIP_init(&s); + mock_link_init(&s); + mock_link_init_idx(&s, TEST_SECOND_IF, iface1_mac); + wolfIP_ipconfig_set(&s, 0xC0A80001U, 0xFFFFFF00U, 0); + wolfIP_ipconfig_set_ex(&s, TEST_SECOND_IF, 0xC0A80101U, 0xFFFFFF00U, 0); + s.arp.neighbors[0].ip = dest_ip; + s.arp.neighbors[0].if_idx = TEST_SECOND_IF; + memcpy(s.arp.neighbors[0].mac, next_hop_mac, 6); + + memset(frame_buf, 0, sizeof(frame_buf)); + memcpy(frame->eth.dst, s.ll_dev[TEST_PRIMARY_IF].mac, 6); + memcpy(frame->eth.src, src_mac, 6); + frame->eth.type = ee16(ETH_TYPE_IP); + frame->ver_ihl = 0x46; /* IHL=6, 24-byte header */ + frame->ttl = 64; + frame->proto = WI_IPPROTO_UDP; + frame->len = ee16(IP_HEADER_LEN + 4); + frame->src = ee32(0xC0A800AAU); /* in TEST_PRIMARY_IF subnet, passes RPF */ + frame->dst = ee32(dest_ip); + + opts[0] = opt_types[i]; + opts[1] = 3; /* option length */ + opts[2] = 4; /* pointer (RFC 791) */ + opts[3] = 0x00; /* end-of-options padding */ + fix_ip_checksum_with_hlen(frame, (uint16_t)(IP_HEADER_LEN + 4)); + + memset(last_frame_sent, 0, sizeof(last_frame_sent)); + last_frame_sent_size = 0; + + wolfIP_recv_ex(&s, TEST_PRIMARY_IF, frame, + (uint32_t)(ETH_HEADER_LEN + IP_HEADER_LEN + 4)); + + ck_assert_uint_eq(last_frame_sent_size, 0); + } +} +END_TEST + START_TEST(test_regression_loopback_source_dropped_on_non_loopback_iface) { static const ip4 spoofed_loopback_sources[] = { @@ -6583,6 +6635,51 @@ START_TEST(test_raw_socket_send_builds_ip_header) } END_TEST +START_TEST(test_regression_raw_socket_send_ip_id_network_byte_order) +{ + struct wolfIP s; + int sd; + uint8_t payload[6] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + struct wolfIP_sockaddr_in sin; + uint32_t dst_ip = 0x0A00000BU; + uint8_t nh_mac[6] = {0x21, 0x22, 0x23, 0x24, 0x25, 0x26}; + uint16_t expected_id; + + wolfIP_init(&s); + mock_link_init(&s); + wolfIP_ipconfig_set(&s, 0x0A000001U, 0xFFFFFF00U, 0); + + s.arp.neighbors[0].ip = dst_ip; + s.arp.neighbors[0].if_idx = TEST_PRIMARY_IF; + memcpy(s.arp.neighbors[0].mac, nh_mac, sizeof(nh_mac)); + + sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_RAW, WI_IPPROTO_UDP); + ck_assert_int_ge(sd, 0); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = ee32(dst_ip); + + last_frame_sent_size = 0; + memset(last_frame_sent, 0, sizeof(last_frame_sent)); + + expected_id = s.ipcounter; + + ck_assert_int_eq(wolfIP_sock_sendto(&s, sd, payload, sizeof(payload), 0, + (struct wolfIP_sockaddr *)&sin, sizeof(sin)), + (int)sizeof(payload)); + wolfIP_poll(&s, 0); + + ck_assert_uint_eq(last_frame_sent_size, + ETH_HEADER_LEN + IP_HEADER_LEN + sizeof(payload)); + { + struct wolfIP_ip_packet *sent = (struct wolfIP_ip_packet *)last_frame_sent; + ck_assert_uint_eq(ee16(sent->id), expected_id); + } + ck_assert_uint_eq(s.ipcounter, (uint16_t)(expected_id + 1)); +} +END_TEST + START_TEST(test_raw_socket_sendto_short_addrlen_returns_einval) { struct wolfIP s; diff --git a/src/test/unit/unit_tests_tcp_ack.c b/src/test/unit/unit_tests_tcp_ack.c index 8fb5a8a..ecec746 100644 --- a/src/test/unit/unit_tests_tcp_ack.c +++ b/src/test/unit/unit_tests_tcp_ack.c @@ -1495,6 +1495,53 @@ START_TEST(test_ip_recv_fragmented_udp_dropped) } END_TEST +START_TEST(test_ip_recv_fragmented_udp_dropped_offset_only) +{ + struct wolfIP s; + struct tsocket *ts; + uint8_t frame[ETH_HEADER_LEN + IP_HEADER_LEN + UDP_HEADER_LEN + 4]; + struct wolfIP_ip_packet *ip = (struct wolfIP_ip_packet *)frame; + uint8_t *udp_hdr = frame + ETH_HEADER_LEN + IP_HEADER_LEN; + uint16_t udp_len = UDP_HEADER_LEN + 4; + uint32_t local_ip = 0x0A000001U; + uint32_t remote_ip = 0x0A000002U; + + wolfIP_init(&s); + mock_link_init(&s); + wolfIP_ipconfig_set(&s, local_ip, 0xFFFFFF00U, 0); + + ts = udp_new_socket(&s); + ck_assert_ptr_nonnull(ts); + ts->src_port = 1234; + ts->local_ip = local_ip; + + memset(frame, 0, sizeof(frame)); + memcpy(ip->eth.dst, s.ll_dev[TEST_PRIMARY_IF].mac, 6); + memcpy(ip->eth.src, "\x01\x02\x03\x04\x05\x06", 6); + ip->eth.type = ee16(ETH_TYPE_IP); + ip->ver_ihl = 0x45; + ip->ttl = 64; + ip->proto = WI_IPPROTO_UDP; + ip->len = ee16(IP_HEADER_LEN + udp_len); + ip->flags_fo = ee16(0x0001U); /* MF=0, offset=1 (byte offset 8) */ + ip->src = ee32(remote_ip); + ip->dst = ee32(local_ip); + + ((uint16_t *)udp_hdr)[0] = ee16(4321); + ((uint16_t *)udp_hdr)[1] = ee16(1234); + ((uint16_t *)udp_hdr)[2] = ee16(udp_len); + memcpy(udp_hdr + UDP_HEADER_LEN, "frag", 4); + + fix_udp_checksum_raw(ip, udp_hdr, udp_len); + fix_ip_checksum(ip); + + ip_recv(&s, TEST_PRIMARY_IF, ip, (uint32_t)sizeof(frame)); + + ck_assert_ptr_eq(fifo_peek(&ts->sock.udp.rxbuf), NULL); + ck_assert_uint_eq(ts->events & CB_EVENT_READABLE, 0); +} +END_TEST + START_TEST(test_ip_recv_forward_arp_queue_and_flush) { struct wolfIP s; diff --git a/src/test/unit/unit_tests_tcp_flow.c b/src/test/unit/unit_tests_tcp_flow.c index 87ee037..54bff3e 100644 --- a/src/test/unit/unit_tests_tcp_flow.c +++ b/src/test/unit/unit_tests_tcp_flow.c @@ -1607,6 +1607,112 @@ START_TEST(test_udp_checksum_zero_accepted) } END_TEST +START_TEST(test_regression_udp_recv_sets_last_pkt_ttl) +{ + struct wolfIP s; + int udp_sd; + int enable = 1; + int recv_ttl = 0; + struct wolfIP_sockaddr_in sin; + struct wolfIP_udp_datagram udp; + struct wolfIP_ll_dev *ll; + static const uint8_t test_ttl = 42; + + wolfIP_init(&s); + mock_link_init(&s); + wolfIP_ipconfig_set(&s, 0x0A000001U, 0xFFFFFF00U, 0); + + udp_sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_UDP); + ck_assert_int_gt(udp_sd, 0); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = ee16(1234); + sin.sin_addr.s_addr = ee32(0x0A000001U); + ck_assert_int_eq(wolfIP_sock_bind(&s, udp_sd, + (struct wolfIP_sockaddr *)&sin, sizeof(sin)), 0); + + ck_assert_int_eq(wolfIP_sock_setsockopt(&s, udp_sd, WOLFIP_SOL_IP, + WOLFIP_IP_RECVTTL, &enable, sizeof(enable)), 0); + + ll = wolfIP_getdev_ex(&s, TEST_PRIMARY_IF); + ck_assert_ptr_nonnull(ll); + + memset(&udp, 0, sizeof(udp)); + memcpy(udp.ip.eth.dst, ll->mac, 6); + udp.ip.eth.type = ee16(ETH_TYPE_IP); + udp.ip.ver_ihl = 0x45; + udp.ip.ttl = test_ttl; + udp.ip.proto = WI_IPPROTO_UDP; + udp.ip.len = ee16(IP_HEADER_LEN + UDP_HEADER_LEN); + udp.ip.src = ee32(0x0A000002U); + udp.ip.dst = ee32(0x0A000001U); + udp.src_port = ee16(5678); + udp.dst_port = ee16(1234); + udp.len = ee16(UDP_HEADER_LEN); + fix_udp_checksums(&udp); + + wolfIP_recv_ex(&s, TEST_PRIMARY_IF, &udp, + (uint32_t)(ETH_HEADER_LEN + IP_HEADER_LEN + UDP_HEADER_LEN)); + + ck_assert_uint_gt(fifo_len(&s.udpsockets[SOCKET_UNMARK(udp_sd)].sock.udp.rxbuf), + 0U); + ck_assert_int_eq(wolfIP_sock_get_recv_ttl(&s, udp_sd, &recv_ttl), 1); + ck_assert_int_eq(recv_ttl, (int)test_ttl); +} +END_TEST + +START_TEST(test_regression_tcp_input_sets_last_pkt_ttl) +{ + struct wolfIP s; + struct tsocket *ts; + struct wolfIP_tcp_seg seg; + int recv_ttl = 0; + int sd; + static const uint8_t test_ttl = 33; + + wolfIP_init(&s); + mock_link_init(&s); + wolfIP_ipconfig_set(&s, 0x0A000001U, 0xFFFFFF00U, 0); + + ts = &s.tcpsockets[0]; + memset(ts, 0, sizeof(*ts)); + ts->proto = WI_IPPROTO_TCP; + ts->S = &s; + ts->sock.tcp.state = TCP_ESTABLISHED; + ts->sock.tcp.ack = 100; + ts->src_port = 1234; + ts->dst_port = 4321; + ts->local_ip = 0x0A000001U; + ts->remote_ip = 0x0A000002U; + ts->recv_ttl = 1; + + memset(&seg, 0, sizeof(seg)); + seg.ip.ver_ihl = 0x45; + seg.ip.ttl = test_ttl; + seg.ip.proto = WI_IPPROTO_TCP; + seg.ip.len = ee16(IP_HEADER_LEN + TCP_HEADER_LEN); + seg.ip.src = ee32(ts->remote_ip); + seg.ip.dst = ee32(ts->local_ip); + seg.dst_port = ee16(ts->src_port); + seg.src_port = ee16(ts->dst_port); + seg.seq = ee32(100); + seg.ack = ee32(50); + seg.hlen = TCP_HEADER_LEN << 2; + seg.flags = TCP_FLAG_ACK; + fix_tcp_checksums(&seg); + + tcp_input(&s, TEST_PRIMARY_IF, &seg, + (uint32_t)(ETH_HEADER_LEN + IP_HEADER_LEN + TCP_HEADER_LEN)); + + ck_assert_uint_eq(ts->last_pkt_ttl, test_ttl); + + sd = (int)((ts - s.tcpsockets) | MARK_TCP_SOCKET); + ck_assert_int_eq(wolfIP_sock_get_recv_ttl(&s, sd, &recv_ttl), 1); + ck_assert_int_eq(recv_ttl, (int)test_ttl); +} +END_TEST + START_TEST(test_udp_connected_rejects_wrong_source_ip) { struct wolfIP s; diff --git a/src/wolfip.c b/src/wolfip.c index c0b458f..d5774d2 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -2305,6 +2305,7 @@ static void udp_try_recv(struct wolfIP *s, unsigned int if_idx, * drop silently instead of misreporting the port as closed. */ matched = 1; if (fifo_push(&t->sock.udp.rxbuf, udp, frame_len) == 0) { + t->last_pkt_ttl = udp->ip.ttl; t->events |= CB_EVENT_READABLE; } } @@ -4593,6 +4594,7 @@ static void tcp_input(struct wolfIP *S, unsigned int if_idx, } } t->if_idx = (uint8_t)if_idx; + t->last_pkt_ttl = tcp->ip.ttl; matched = 1; /* Validate minimum TCP header length (data offset). */ if (tcp_data_offset_bytes(tcp->hlen) < TCP_HEADER_LEN) { @@ -5352,6 +5354,8 @@ int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockad unsigned int if_idx; if ((!addr)|| (sockfd < 0)) return -WOLFIP_EINVAL; + if (!s) + return -WOLFIP_EINVAL; sin = (const struct wolfIP_sockaddr_in *)addr; if (IS_SOCKET_UDP(sockfd)) { struct ipconf *conf; @@ -5515,6 +5519,9 @@ int wolfIP_sock_accept(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *add if (sockfd < 0) return -WOLFIP_EINVAL; + if (!s) + return -WOLFIP_EINVAL; + if (addrlen) *addrlen = sizeof(struct wolfIP_sockaddr_in); @@ -5621,6 +5628,9 @@ int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len if (sockfd < 0) return -WOLFIP_EINVAL; + if (!s) + return -WOLFIP_EINVAL; + if ((!buf) || (len == 0)) return -1; @@ -5897,7 +5907,7 @@ int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len rip->ver_ihl = 0x45; rip->tos = 0; rip->len = ee16((uint16_t)(len + IP_HEADER_LEN)); - rip->id = ee16(ipcounter_next(s)); + rip->id = ipcounter_next(s); rip->flags_fo = 0; rip->ttl = 64; rip->proto = (uint8_t)rs->protocol; @@ -5994,6 +6004,9 @@ int wolfIP_sock_recvfrom(struct wolfIP *s, int sockfd, void *buf, size_t len, in if (sockfd < 0) return -WOLFIP_EINVAL; + if (!s) + return -WOLFIP_EINVAL; + if (IS_SOCKET_TCP(sockfd)) { if (SOCKET_UNMARK(sockfd) >= MAX_TCPSOCKETS) return -WOLFIP_EINVAL; @@ -6579,6 +6592,8 @@ int wolfIP_sock_close(struct wolfIP *s, int sockfd) { if (sockfd < 0) return -WOLFIP_EINVAL; + if (!s) + return -WOLFIP_EINVAL; if (IS_SOCKET_TCP(sockfd)) { struct tsocket *ts; if (SOCKET_UNMARK(sockfd) >= MAX_TCPSOCKETS) @@ -6670,6 +6685,9 @@ int wolfIP_sock_getsockname(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr if ((!addr) || (sockfd < 0)) return -WOLFIP_EINVAL; + if (!s) + return -WOLFIP_EINVAL; + sin = (struct wolfIP_sockaddr_in *)addr; if (!sin || (addrlen && *addrlen < sizeof(struct wolfIP_sockaddr_in))) return -1; @@ -6844,6 +6862,9 @@ int wolfIP_sock_bind(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr if (sockfd < 0) return -WOLFIP_EINVAL; + if (!s) + return -WOLFIP_EINVAL; + #if WOLFIP_PACKET_SOCKETS if (IS_SOCKET_PACKET(sockfd)) { struct packetsocket *ps = wolfIP_packetsocket_from_fd(s, sockfd); @@ -7022,6 +7043,8 @@ int wolfIP_sock_listen(struct wolfIP *s, int sockfd, int backlog) (void)backlog; if (sockfd < 0) return -WOLFIP_EINVAL; + if (!s) + return -WOLFIP_EINVAL; if (IS_SOCKET_TCP(sockfd)) { if (SOCKET_UNMARK(sockfd) >= MAX_TCPSOCKETS) return -WOLFIP_EINVAL; @@ -7049,6 +7072,8 @@ int wolfIP_sock_getpeername(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr struct wolfIP_sockaddr_in *sin = (struct wolfIP_sockaddr_in *)addr; if (sockfd < 0) return -WOLFIP_EINVAL; + if (!s) + return -WOLFIP_EINVAL; if (IS_SOCKET_TCP(sockfd)) { if (SOCKET_UNMARK(sockfd) >= MAX_TCPSOCKETS) return -WOLFIP_EINVAL; @@ -8361,6 +8386,29 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, #if WOLFIP_RAWSOCKETS raw_try_recv(s, if_idx, ip, len); #endif + /* RFC 7126 section 3.8: drop source-routed (LSRR/SSRR) packets before either + * forwarding or local-delivery dispatch. + * */ + if (ip_hlen > IP_HEADER_LEN) { + uint8_t *opt = ((uint8_t *)ip) + ETH_HEADER_LEN + IP_HEADER_LEN; + uint8_t *opt_end = opt + (ip_hlen - IP_HEADER_LEN); + while (opt < opt_end) { + uint8_t type = *opt; + if (type == 0) /* End of Options */ + break; + if (type == 1) { /* NOP */ + opt++; + continue; + } + if (type == 0x83 || type == 0x89) /* LSRR or SSRR */ + return; + if (opt + 1 >= opt_end || opt[1] < 2) + break; + if (opt[1] > (uint8_t)(opt_end - opt)) + return; + opt += opt[1]; + } + } #if WOLFIP_ENABLE_FORWARDING if (version == 4 && ip_hlen >= IP_HEADER_LEN) { ip4 dest = ee32(ip->dst); @@ -8472,26 +8520,6 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, uint32_t opt_len = ip_hlen - IP_HEADER_LEN; uint16_t total_ip_len = ee16(ip->len); - /* RFC 7126 ยง3.8: drop source-routed packets. */ - { - uint8_t *opt = ((uint8_t *)ip) + ETH_HEADER_LEN + IP_HEADER_LEN; - uint8_t *opt_end = opt + opt_len; - while (opt < opt_end) { - uint8_t type = *opt; - if (type == 0) /* End of Options */ - break; - if (type == 1) { /* NOP */ - opt++; - continue; - } - if (type == 0x83 || type == 0x89) /* LSRR or SSRR */ - return; - if (opt + 1 >= opt_end || opt[1] < 2) - break; - opt += opt[1]; - } - } - if (len > LINK_MTU) return; memcpy(frame, ip, len);