1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2024 Oxide Computer Company 14 */ 15 16 /* 17 * Basic tests to verify that SO_PROTOCOL, SO_DOMAIN, and SO_TYPE perform as we 18 * expect. 19 */ 20 21 #include <stdlib.h> 22 #include <stdbool.h> 23 #include <sys/types.h> 24 #include <sys/socket.h> 25 #include <stdio.h> 26 #include <err.h> 27 #include <unistd.h> 28 #include <sys/sysmacros.h> 29 #include <sys/debug.h> 30 #include <net/pfkeyv2.h> 31 #include <net/pfpolicy.h> 32 33 typedef struct { 34 const char *sp_desc; 35 int sp_dom; 36 int sp_type; 37 int sp_prot; 38 int sp_expprot; 39 bool sp_noproto; 40 } so_prot_test_t; 41 42 static const so_prot_test_t so_prot_tests[] = { { 43 .sp_desc = "IPv4 TCP (prot=0)", 44 .sp_dom = PF_INET, 45 .sp_type = SOCK_STREAM, 46 .sp_prot = 0, 47 .sp_expprot = IPPROTO_TCP 48 }, { 49 .sp_desc = "IPv4 TCP (prot=TCP)", 50 .sp_dom = PF_INET, 51 .sp_type = SOCK_STREAM, 52 .sp_prot = IPPROTO_TCP, 53 .sp_expprot = IPPROTO_TCP 54 }, { 55 .sp_desc = "IPv4 UDP (prot=0)", 56 .sp_dom = PF_INET, 57 .sp_type = SOCK_DGRAM, 58 .sp_prot = 0, 59 .sp_expprot = IPPROTO_UDP 60 }, { 61 .sp_desc = "IPv4 UDP (prot=UDP)", 62 .sp_dom = PF_INET, 63 .sp_type = SOCK_DGRAM, 64 .sp_prot = IPPROTO_UDP, 65 .sp_expprot = IPPROTO_UDP 66 }, { 67 .sp_desc = "IPv4 SCTP (type=STREAM)", 68 .sp_dom = PF_INET, 69 .sp_type = SOCK_STREAM, 70 .sp_prot = IPPROTO_SCTP, 71 .sp_expprot = IPPROTO_SCTP 72 }, { 73 .sp_desc = "IPv4 SCTP (type=SEQPACKET)", 74 .sp_dom = PF_INET, 75 .sp_type = SOCK_SEQPACKET, 76 .sp_prot = IPPROTO_SCTP, 77 .sp_expprot = IPPROTO_SCTP 78 }, { 79 .sp_desc = "IPv6 TCP (prot=0)", 80 .sp_dom = PF_INET6, 81 .sp_type = SOCK_STREAM, 82 .sp_prot = 0, 83 .sp_expprot = IPPROTO_TCP 84 }, { 85 .sp_desc = "IPv6 TCP (prot=TCP)", 86 .sp_dom = PF_INET6, 87 .sp_type = SOCK_STREAM, 88 .sp_prot = IPPROTO_TCP, 89 .sp_expprot = IPPROTO_TCP 90 }, { 91 .sp_desc = "IPv6 UDP (prot=0)", 92 .sp_dom = PF_INET6, 93 .sp_type = SOCK_DGRAM, 94 .sp_prot = 0, 95 .sp_expprot = IPPROTO_UDP 96 }, { 97 .sp_desc = "IPv6 UDP (prot=UDP)", 98 .sp_dom = PF_INET6, 99 .sp_type = SOCK_DGRAM, 100 .sp_prot = IPPROTO_UDP, 101 .sp_expprot = IPPROTO_UDP 102 }, { 103 .sp_desc = "IPv6 SCTP (type=STREAM)", 104 .sp_dom = PF_INET6, 105 .sp_type = SOCK_STREAM, 106 .sp_prot = IPPROTO_SCTP, 107 .sp_expprot = IPPROTO_SCTP 108 }, { 109 .sp_desc = "IPv6 SCTP (type=SEQPACKET)", 110 .sp_dom = PF_INET6, 111 .sp_type = SOCK_SEQPACKET, 112 .sp_prot = IPPROTO_SCTP, 113 .sp_expprot = IPPROTO_SCTP 114 }, { 115 .sp_desc = "UDS (type=STREAM)", 116 .sp_dom = PF_UNIX, 117 .sp_type = SOCK_STREAM, 118 .sp_prot = 0, 119 .sp_expprot = 0 120 }, { 121 .sp_desc = "UDS (type=DGRAM)", 122 .sp_dom = PF_UNIX, 123 .sp_type = SOCK_DGRAM, 124 .sp_prot = 0, 125 .sp_expprot = 0 126 }, { 127 .sp_desc = "UDS (type=SEQPACKET)", 128 .sp_dom = PF_UNIX, 129 .sp_type = SOCK_SEQPACKET, 130 .sp_prot = 0, 131 .sp_expprot = 0 132 }, { 133 .sp_desc = "PF_KEY", 134 .sp_dom = PF_KEY, 135 .sp_type = SOCK_RAW, 136 .sp_prot = PF_KEY_V2, 137 .sp_expprot = PF_KEY_V2 138 }, { 139 .sp_desc = "PF_POLICY", 140 .sp_dom = PF_POLICY, 141 .sp_type = SOCK_RAW, 142 .sp_prot = PF_POLICY_V1, 143 .sp_expprot = PF_POLICY_V1 144 }, { 145 .sp_desc = "ICMP", 146 .sp_dom = PF_INET, 147 .sp_type = SOCK_RAW, 148 .sp_prot = IPPROTO_ICMP, 149 .sp_expprot = IPPROTO_ICMP 150 }, { 151 .sp_desc = "ICMPv6", 152 .sp_dom = PF_INET6, 153 .sp_type = SOCK_RAW, 154 .sp_prot = IPPROTO_ICMPV6, 155 .sp_expprot = IPPROTO_ICMPV6 156 }, { 157 .sp_desc = "PF_ROUTE (IPv4)", 158 .sp_dom = PF_ROUTE, 159 .sp_type = SOCK_RAW, 160 .sp_prot = AF_INET, 161 .sp_expprot = AF_INET 162 }, { 163 .sp_desc = "PF_ROUTE (IPv6)", 164 .sp_dom = PF_ROUTE, 165 .sp_type = SOCK_RAW, 166 .sp_prot = AF_INET6, 167 .sp_expprot = AF_INET6 168 }, { 169 .sp_desc = "PF_ROUTE (IPv4+IPv6)", 170 .sp_dom = PF_ROUTE, 171 .sp_type = SOCK_RAW, 172 .sp_prot = 0, 173 .sp_expprot = 0 174 }, { 175 .sp_desc = "Trill", 176 .sp_dom = PF_TRILL, 177 .sp_type = SOCK_DGRAM, 178 .sp_prot = 0, 179 .sp_expprot = 0 180 } }; 181 182 static bool 183 so_test_one(const so_prot_test_t *test) 184 { 185 int s, opt; 186 socklen_t len; 187 bool ret = true; 188 189 s = socket(test->sp_dom, test->sp_type, test->sp_prot); 190 if (s < 0) { 191 warn("TEST FAILED: %s: failed to create socket with " 192 "domain/type/protocol 0x%x/0x%x/0x%x", test->sp_desc, 193 test->sp_dom, test->sp_type, test->sp_prot); 194 return (false); 195 } 196 197 len = sizeof (opt); 198 if (getsockopt(s, SOL_SOCKET, SO_DOMAIN, &opt, &len) != 0) { 199 warn("TEST FAILED: %s: failed to get SO_DOMAIN", test->sp_desc); 200 ret = false; 201 } else if (opt != test->sp_dom) { 202 warnx("TEST FAILED: %s: expected domain 0x%x, but found 0x%x", 203 test->sp_desc, test->sp_dom, opt); 204 ret = false; 205 } else { 206 (void) printf("TEST PASSED: %s: received correct domain\n", 207 test->sp_desc); 208 } 209 210 len = sizeof (opt); 211 if (getsockopt(s, SOL_SOCKET, SO_TYPE, &opt, &len) != 0) { 212 warn("TEST FAILED: %s: failed to get SO_TYPE", test->sp_desc); 213 ret = false; 214 } else if (opt != test->sp_type) { 215 warnx("TEST FAILED: %s: expected type 0x%x, but found 0x%x", 216 test->sp_desc, test->sp_type, opt); 217 ret = false; 218 } else { 219 (void) printf("TEST PASSED: %s: received correct type\n", 220 test->sp_desc); 221 } 222 223 len = sizeof (opt); 224 if (getsockopt(s, SOL_SOCKET, SO_PROTOCOL, &opt, &len) != 0) { 225 warn("TEST FAILED: %s: failed to get SO_PROTOCOL", 226 test->sp_desc); 227 ret = false; 228 } else if (opt != test->sp_expprot) { 229 warnx("TEST FAILED: %s: expected protocol 0x%x, but found 0x%x", 230 test->sp_desc, test->sp_expprot, opt); 231 ret = false; 232 } else { 233 (void) printf("TEST PASSED: %s: received correct protocol\n", 234 test->sp_desc); 235 } 236 237 VERIFY0(close(s)); 238 return (ret); 239 } 240 241 int 242 main(void) 243 { 244 int ret = EXIT_SUCCESS; 245 246 for (size_t i = 0; i < ARRAY_SIZE(so_prot_tests); i++) { 247 if (!so_test_one(&so_prot_tests[i])) 248 ret = EXIT_FAILURE; 249 } 250 251 if (ret == EXIT_SUCCESS) 252 (void) printf("All tests passed successfully\n"); 253 return (ret); 254 } 255