Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftest/tcp-ao: Add filter tests

Add tests that check if getsockopt(TCP_AO_GET_KEYS) returns the right
keys when using different filters.

Sample output:

> # ok 114 filter keys: by sndid, rcvid, address
> # ok 115 filter keys: by is_current
> # ok 116 filter keys: by is_rnext
> # ok 117 filter keys: by sndid, rcvid
> # ok 118 filter keys: correct nkeys when in.nkeys < matches

Acked-by: Dmitry Safonov <0x7f454c46@gmail.com>
Signed-off-by: Leo Stone <leocstone@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20241021174652.6949-1-leocstone@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Leo Stone and committed by
Jakub Kicinski
47e99f30 9f6cb319

+181 -5
+181 -5
tools/testing/selftests/net/tcp_ao/setsockopt-closed.c
··· 6 6 7 7 static union tcp_addr tcp_md5_client; 8 8 9 + #define FILTER_TEST_NKEYS 16 10 + 9 11 static int test_port = 7788; 10 12 static void make_listen(int sk) 11 13 { ··· 815 813 setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: SendID differs"); 816 814 } 817 815 816 + static void fetch_all_keys(int sk, struct tcp_ao_getsockopt *keys) 817 + { 818 + socklen_t optlen = sizeof(struct tcp_ao_getsockopt); 819 + 820 + memset(keys, 0, sizeof(struct tcp_ao_getsockopt) * FILTER_TEST_NKEYS); 821 + keys[0].get_all = 1; 822 + keys[0].nkeys = FILTER_TEST_NKEYS; 823 + if (getsockopt(sk, IPPROTO_TCP, TCP_AO_GET_KEYS, &keys[0], &optlen)) 824 + test_error("getsockopt"); 825 + } 826 + 827 + static int prepare_test_keys(struct tcp_ao_getsockopt *keys) 828 + { 829 + const char *test_password = "Test password number "; 830 + struct tcp_ao_add test_ao[FILTER_TEST_NKEYS]; 831 + char test_password_scratch[64] = {}; 832 + u8 rcvid = 100, sndid = 100; 833 + int sk; 834 + 835 + sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP); 836 + if (sk < 0) 837 + test_error("socket()"); 838 + 839 + for (int i = 0; i < FILTER_TEST_NKEYS; i++) { 840 + snprintf(test_password_scratch, 64, "%s %d", test_password, i); 841 + test_prepare_key(&test_ao[i], DEFAULT_TEST_ALGO, this_ip_dest, 842 + false, false, DEFAULT_TEST_PREFIX, 0, sndid++, 843 + rcvid++, 0, 0, strlen(test_password_scratch), 844 + test_password_scratch); 845 + } 846 + test_ao[0].set_current = 1; 847 + test_ao[1].set_rnext = 1; 848 + /* One key with a different addr and overlapping sndid, rcvid */ 849 + tcp_addr_to_sockaddr_in(&test_ao[2].addr, &this_ip_addr, 0); 850 + test_ao[2].sndid = 100; 851 + test_ao[2].rcvid = 100; 852 + 853 + /* Add keys in a random order */ 854 + for (int i = 0; i < FILTER_TEST_NKEYS; i++) { 855 + int randidx = rand() % (FILTER_TEST_NKEYS - i); 856 + 857 + if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, 858 + &test_ao[randidx], sizeof(struct tcp_ao_add))) 859 + test_error("setsockopt()"); 860 + memcpy(&test_ao[randidx], &test_ao[FILTER_TEST_NKEYS - 1 - i], 861 + sizeof(struct tcp_ao_add)); 862 + } 863 + 864 + fetch_all_keys(sk, keys); 865 + 866 + return sk; 867 + } 868 + 869 + /* Assumes passwords are unique */ 870 + static int compare_mkts(struct tcp_ao_getsockopt *expected, int nexpected, 871 + struct tcp_ao_getsockopt *actual, int nactual) 872 + { 873 + int matches = 0; 874 + 875 + for (int i = 0; i < nexpected; i++) { 876 + for (int j = 0; j < nactual; j++) { 877 + if (memcmp(expected[i].key, actual[j].key, 878 + TCP_AO_MAXKEYLEN) == 0) 879 + matches++; 880 + } 881 + } 882 + return nexpected - matches; 883 + } 884 + 885 + static void filter_keys_checked(int sk, struct tcp_ao_getsockopt *filter, 886 + struct tcp_ao_getsockopt *expected, 887 + unsigned int nexpected, const char *tst) 888 + { 889 + struct tcp_ao_getsockopt filtered_keys[FILTER_TEST_NKEYS] = {}; 890 + struct tcp_ao_getsockopt all_keys[FILTER_TEST_NKEYS] = {}; 891 + socklen_t len = sizeof(struct tcp_ao_getsockopt); 892 + 893 + fetch_all_keys(sk, all_keys); 894 + memcpy(&filtered_keys[0], filter, sizeof(struct tcp_ao_getsockopt)); 895 + filtered_keys[0].nkeys = FILTER_TEST_NKEYS; 896 + if (getsockopt(sk, IPPROTO_TCP, TCP_AO_GET_KEYS, filtered_keys, &len)) 897 + test_error("getsockopt"); 898 + if (filtered_keys[0].nkeys != nexpected) { 899 + test_fail("wrong nr of keys, expected %u got %u", nexpected, 900 + filtered_keys[0].nkeys); 901 + goto out_close; 902 + } 903 + if (compare_mkts(expected, nexpected, filtered_keys, 904 + filtered_keys[0].nkeys)) { 905 + test_fail("got wrong keys back"); 906 + goto out_close; 907 + } 908 + test_ok("filter keys: %s", tst); 909 + 910 + out_close: 911 + close(sk); 912 + memset(filter, 0, sizeof(struct tcp_ao_getsockopt)); 913 + } 914 + 915 + static void filter_tests(void) 916 + { 917 + struct tcp_ao_getsockopt original_keys[FILTER_TEST_NKEYS]; 918 + struct tcp_ao_getsockopt expected_keys[FILTER_TEST_NKEYS]; 919 + struct tcp_ao_getsockopt filter = {}; 920 + int sk, f, nmatches; 921 + socklen_t len; 922 + 923 + f = 2; 924 + sk = prepare_test_keys(original_keys); 925 + filter.rcvid = original_keys[f].rcvid; 926 + filter.sndid = original_keys[f].sndid; 927 + memcpy(&filter.addr, &original_keys[f].addr, 928 + sizeof(original_keys[f].addr)); 929 + filter.prefix = original_keys[f].prefix; 930 + filter_keys_checked(sk, &filter, &original_keys[f], 1, 931 + "by sndid, rcvid, address"); 932 + 933 + f = -1; 934 + sk = prepare_test_keys(original_keys); 935 + for (int i = 0; i < original_keys[0].nkeys; i++) { 936 + if (original_keys[i].is_current) { 937 + f = i; 938 + break; 939 + } 940 + } 941 + if (f < 0) 942 + test_error("No current key after adding one"); 943 + filter.is_current = 1; 944 + filter_keys_checked(sk, &filter, &original_keys[f], 1, "by is_current"); 945 + 946 + f = -1; 947 + sk = prepare_test_keys(original_keys); 948 + for (int i = 0; i < original_keys[0].nkeys; i++) { 949 + if (original_keys[i].is_rnext) { 950 + f = i; 951 + break; 952 + } 953 + } 954 + if (f < 0) 955 + test_error("No rnext key after adding one"); 956 + filter.is_rnext = 1; 957 + filter_keys_checked(sk, &filter, &original_keys[f], 1, "by is_rnext"); 958 + 959 + f = -1; 960 + nmatches = 0; 961 + sk = prepare_test_keys(original_keys); 962 + for (int i = 0; i < original_keys[0].nkeys; i++) { 963 + if (original_keys[i].sndid == 100) { 964 + f = i; 965 + memcpy(&expected_keys[nmatches], &original_keys[i], 966 + sizeof(struct tcp_ao_getsockopt)); 967 + nmatches++; 968 + } 969 + } 970 + if (f < 0) 971 + test_error("No key for sndid 100"); 972 + if (nmatches != 2) 973 + test_error("Should have 2 keys with sndid 100"); 974 + filter.rcvid = original_keys[f].rcvid; 975 + filter.sndid = original_keys[f].sndid; 976 + filter.addr.ss_family = test_family; 977 + filter_keys_checked(sk, &filter, expected_keys, nmatches, 978 + "by sndid, rcvid"); 979 + 980 + sk = prepare_test_keys(original_keys); 981 + filter.get_all = 1; 982 + filter.nkeys = FILTER_TEST_NKEYS / 2; 983 + len = sizeof(struct tcp_ao_getsockopt); 984 + if (getsockopt(sk, IPPROTO_TCP, TCP_AO_GET_KEYS, &filter, &len)) 985 + test_error("getsockopt"); 986 + if (filter.nkeys == FILTER_TEST_NKEYS) 987 + test_ok("filter keys: correct nkeys when in.nkeys < matches"); 988 + else 989 + test_fail("filter keys: wrong nkeys, expected %u got %u", 990 + FILTER_TEST_NKEYS, filter.nkeys); 991 + } 992 + 818 993 static void *client_fn(void *arg) 819 994 { 820 995 if (inet_pton(TEST_FAMILY, __TEST_CLIENT_IP(2), &tcp_md5_client) != 1) 821 996 test_error("Can't convert ip address"); 822 997 extend_tests(); 823 998 einval_tests(); 999 + filter_tests(); 824 1000 duplicate_tests(); 825 - /* 826 - * TODO: check getsockopt(TCP_AO_GET_KEYS) with different filters 827 - * returning proper nr & keys; 828 - */ 829 1001 830 1002 return NULL; 831 1003 } 832 1004 833 1005 int main(int argc, char *argv[]) 834 1006 { 835 - test_init(121, client_fn, NULL); 1007 + test_init(126, client_fn, NULL); 836 1008 return 0; 837 1009 }