Changeset 2d1da0d in rtems-libbsd for testsuite/pf01/test_main.c
- Timestamp:
- Jul 22, 2016, 12:50:09 PM (5 years ago)
- Branches:
- 4.11
- Children:
- c3a8e6b
- Parents:
- b0eda36
- git-author:
- Christian Mauderer <Christian.Mauderer@…> (07/22/16 12:50:09)
- git-committer:
- Sebastian Huber <sebastian.huber@…> (08/03/16 12:13:19)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
testsuite/pf01/test_main.c
rb0eda36 r2d1da0d 30 30 */ 31 31 32 #include <assert.h> 33 #include <fcntl.h> 34 #include <stdio.h> 32 35 #include <stdlib.h> 36 #include <sys/stat.h> 37 #include <sys/socket.h> 38 #include <netinet/in.h> 39 #include <netinet/tcp.h> 40 #include <netdb.h> 41 #include <unistd.h> 42 #include <errno.h> 43 44 #include <machine/rtems-bsd-commands.h> 45 46 #include <rtems/libcsupport.h> 47 #include <rtems/shell.h> 48 #include <rtems/telnetd.h> 49 #include <rtems/ftpd.h> 33 50 34 51 #define TEST_NAME "LIBBSD PF 1" 35 52 53 #define ARGC(x) RTEMS_BSD_ARGC(x) 54 55 #define LO1_IP "172.21.1.1" 56 #define LO2_IP "172.22.2.2" 57 #define TELNET_PORT 23 58 #define FTP_PORT 21 59 60 #define SERVER_TASK_PRIO 110 61 62 /* 63 * WARNING: The following rules are not made to be an good example for using PF. 64 * Check the online manuals for PF to find out how to write good rules. 65 */ 66 67 /* Config with invalid syntax */ 68 #define TEST_CFG_INVALID "/etc/pf_invalid.conf" 69 #define TEST_CFG_INVALID_CONTENT \ 70 "some\n" \ 71 "garbage\n" 72 73 /* Allow only some services on output. */ 74 #define TEST_CFG_BLOCK_MOST "/etc/pf_block_most.conf" 75 #define TEST_CFG_BLOCK_MOST_CONTENT \ 76 "tcp_services = \"{ ssh, telnet, www }\"\n" \ 77 "udp_services = \"{ telnet }\"\n" \ 78 "block all\n" \ 79 "pass out proto tcp to any port $tcp_services keep state\n" \ 80 "pass proto udp to any port $udp_services keep state\n" 81 82 /* Allow all on one and only some on another interface. */ 83 #define TEST_CFG_IF_DEPEND "/etc/pf_if_depend.conf" 84 #define TEST_CFG_IF_DEPEND_CONTENT \ 85 "ext_if = \"cgem0\"\n" \ 86 "int_if = \"lo0\"\n" \ 87 "block in all\n" \ 88 "pass in on $int_if all\n" \ 89 "pass in on $ext_if inet proto { tcp, udp } from any port { telnet }\n" 90 91 /* Block all input except on lo1. */ 92 #define TEST_CFG_ALLOW_LO1 "/etc/pf_allow_lo1.conf" 93 #define TEST_CFG_ALLOW_LO1_CONTENT \ 94 "block all\n" \ 95 "pass in on lo1 all keep state\n" \ 96 "pass out all\n" 97 98 /* Block all input except telnet on lo1. */ 99 #define TEST_CFG_TELNET_LO1 "/etc/pf_allow_telnet_lo1.conf" 100 #define TEST_CFG_TELNET_LO1_CONTENT \ 101 "block all\n" \ 102 "pass in on lo1 inet proto { tcp } from any to any port { telnet } keep state\n" \ 103 "pass out all\n" 104 105 /* pf.os */ 106 #define ETC_PF_OS "/etc/pf.os" 107 #define ETC_PF_OS_CONTENT "# empty" 108 109 /* protocols */ 110 #define ETC_PROTOCOLS "/etc/protocols" 111 #define ETC_PROTOCOLS_CONTENT \ 112 "ip 0 IP # internet protocol, pseudo protocol number\n" \ 113 "tcp 6 TCP # transmission control protocol\n" \ 114 "udp 17 UDP # user datagram protocol\n" 115 116 /* services */ 117 #define ETC_SERVICES "/etc/services" 118 #define ETC_SERVICES_CONTENT \ 119 "ftp-data 20/sctp #File Transfer [Default Data]\n" \ 120 "ftp-data 20/tcp #File Transfer [Default Data]\n" \ 121 "ftp-data 20/udp #File Transfer [Default Data]\n" \ 122 "ftp 21/sctp #File Transfer [Control]\n" \ 123 "ftp 21/tcp #File Transfer [Control]\n" \ 124 "ftp 21/udp #File Transfer [Control]\n" \ 125 "ssh 22/tcp #Secure Shell Login\n" \ 126 "telnet 23/tcp\n" \ 127 "telnet 23/udp\n" \ 128 "http 80/tcp www www-http #World Wide Web HTTP\n" 129 130 static const struct { 131 const char *name; 132 const char *content; 133 } init_files[] = { 134 {.name = ETC_PF_OS, .content = ETC_PF_OS_CONTENT}, 135 {.name = ETC_PROTOCOLS, .content = ETC_PROTOCOLS_CONTENT}, 136 {.name = ETC_SERVICES, .content = ETC_SERVICES_CONTENT}, 137 {.name = TEST_CFG_INVALID, .content = TEST_CFG_INVALID_CONTENT}, 138 {.name = TEST_CFG_BLOCK_MOST, .content = TEST_CFG_BLOCK_MOST_CONTENT}, 139 {.name = TEST_CFG_IF_DEPEND, .content = TEST_CFG_IF_DEPEND_CONTENT}, 140 {.name = TEST_CFG_ALLOW_LO1, .content = TEST_CFG_ALLOW_LO1_CONTENT}, 141 {.name = TEST_CFG_TELNET_LO1, .content = TEST_CFG_TELNET_LO1_CONTENT}, 142 }; 143 144 /* Create all necessary files */ 145 static void 146 prepare_files() 147 { 148 size_t i; 149 struct stat sb; 150 int rv; 151 int fd; 152 size_t written; 153 154 /* Create /etc if necessary */ 155 rv = mkdir("/etc", S_IRWXU | S_IRWXG | S_IRWXO); 156 /* ignore errors, check the dir after. */ 157 assert(stat("/etc", &sb) == 0); 158 assert(S_ISDIR(sb.st_mode)); 159 160 /* Create files */ 161 for(i = 0; i < (sizeof(init_files)/sizeof(init_files[0])); ++i) { 162 const char *content; 163 size_t len; 164 165 content = init_files[i].content; 166 len = strlen(content); 167 168 fd = open(init_files[i].name, O_WRONLY | O_CREAT, 169 S_IRWXU | S_IRWXG | S_IRWXO); 170 assert(fd != -1); 171 172 written = write(fd, content, len); 173 assert(written == len); 174 175 rv = close(fd); 176 assert(rv == 0); 177 } 178 } 179 180 /* Generic server task */ 181 static rtems_task 182 tcp_server_task(rtems_task_argument arg) 183 { 184 int sd, client; 185 socklen_t addrlen; 186 struct sockaddr_in addr, client_addr; 187 uint16_t port = arg; 188 int rv; 189 const char answer[] = "I am a dummy\n"; 190 191 sd = socket(AF_INET, SOCK_STREAM, 0); 192 assert(sd > 0); 193 194 memset(&addr, 0, sizeof addr); 195 addr.sin_family = AF_INET; 196 addr.sin_addr.s_addr = INADDR_ANY; 197 addr.sin_port = htons(port); 198 199 rv = bind(sd, (struct sockaddr *)&addr, sizeof(addr)); 200 assert(rv == 0); 201 202 rv = listen(sd, 10); 203 assert(rv == 0); 204 205 for(;;) { 206 addrlen = sizeof(client_addr); 207 client = accept(sd, (struct sockaddr *)&client_addr, &addrlen); 208 if(client > 0) { 209 write(client, answer, strlen(answer)); 210 close(client); 211 } 212 } 213 } 214 215 static void 216 spawn_server(uint16_t port) 217 { 218 rtems_status_code sc; 219 rtems_id tid; 220 221 sc = rtems_task_create(rtems_build_name('s','r','v',' '), 222 SERVER_TASK_PRIO, 223 RTEMS_MINIMUM_STACK_SIZE, 224 RTEMS_DEFAULT_MODES, 225 RTEMS_DEFAULT_ATTRIBUTES, 226 &tid); 227 assert(sc == RTEMS_SUCCESSFUL); 228 sc = rtems_task_start(tid, tcp_server_task, port); 229 assert(sc == RTEMS_SUCCESSFUL); 230 } 231 232 /* Start a few services to test */ 233 static void 234 prepare_services() 235 { 236 spawn_server(TELNET_PORT); 237 spawn_server(FTP_PORT); 238 } 239 240 /* Create some additional loopback interfaces for the test. */ 241 static void 242 prepare_interfaces() 243 { 244 int exit_code; 245 char *lo1[] = { 246 "ifconfig", "lo1", "create", "inet", LO1_IP, 247 "netmask", "255.255.0.0", NULL 248 }; 249 char *lo2[] = { 250 "ifconfig", "lo2", "create", "inet", LO2_IP, 251 "netmask", "255.255.0.0", NULL 252 }; 253 254 puts("--- create lo1 and lo2"); 255 exit_code = rtems_bsd_command_ifconfig(ARGC(lo1), lo1); 256 assert(exit_code == EXIT_SUCCESS); 257 exit_code = rtems_bsd_command_ifconfig(ARGC(lo2), lo2); 258 assert(exit_code == EXIT_SUCCESS); 259 } 260 261 static void 262 check_tcp_port(char *host, bool expect_open, uint16_t port) 263 { 264 int sd; 265 struct sockaddr_in addr; 266 struct hostent *server; 267 int rv; 268 struct timeval tv; 269 fd_set select_set; 270 271 sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 272 assert(sd > 0); 273 274 /* make socket nonblocking */ 275 rv = fcntl(sd, F_GETFL, NULL); 276 assert(rv >= 0); 277 rv |= O_NONBLOCK; 278 rv = fcntl(sd, F_SETFL, rv); 279 assert(rv == 0); 280 281 memset(&addr, 0, sizeof(addr)); 282 addr.sin_family = AF_INET; 283 addr.sin_port = htons(port); 284 285 server = gethostbyname(host); 286 assert(server != NULL); 287 memcpy(&addr.sin_addr.s_addr, server->h_addr, server->h_length); 288 289 rv = connect(sd, (struct sockaddr *)&addr, sizeof(addr)); 290 if(rv == 0) { 291 /* successfully connected */ 292 assert(expect_open == true); 293 } else { 294 if(errno != EINPROGRESS) { 295 assert(expect_open == false); 296 } else { 297 /* wait for connection or timeout */ 298 memset(&tv, 0, sizeof(tv)); 299 tv.tv_usec = 100000; 300 301 FD_ZERO(&select_set); 302 FD_SET(sd, &select_set); 303 rv = select(sd+1, NULL, &select_set, NULL, &tv); 304 305 /* rv < 0 would be an error 306 * rv == 0 would be an timeout 307 * rv > 0 would be success */ 308 if(expect_open == false) { 309 assert(rv == 0); 310 } else { 311 assert(rv > 0); 312 } 313 } 314 } 315 316 rv = close(sd); 317 assert(rv == 0); 318 } 319 320 static void 321 check_telnet(char *host, bool expect_open) 322 { 323 check_tcp_port(host, expect_open, TELNET_PORT); 324 } 325 326 static void 327 check_ftp(char *host, bool expect_open) 328 { 329 check_tcp_port(host, expect_open, FTP_PORT); 330 } 331 332 /* Check if services work like expected */ 333 static void 334 check_services(char *host, bool exp_telnet, bool exp_ftp) 335 { 336 check_telnet(host, exp_telnet); 337 check_ftp(host, exp_ftp); 338 } 339 340 static void 341 disable_pf(bool ignore_not_enabled) 342 { 343 int exit_code; 344 char *pfctl[] = {"pfctl", "-d", "-q", NULL}; 345 346 exit_code = rtems_bsd_command_pfctl(ARGC(pfctl), pfctl); 347 assert(ignore_not_enabled || (exit_code == EXIT_SUCCESS)); 348 } 349 350 static void 351 enable_pf() 352 { 353 int exit_code; 354 char *pfctl[] = {"pfctl", "-e", "-q", NULL}; 355 356 exit_code = rtems_bsd_command_pfctl(ARGC(pfctl), pfctl); 357 assert(exit_code == EXIT_SUCCESS); 358 } 359 360 /* Execute pfctl two times with the given arguments. Check the resources. */ 361 static void 362 run_pfctl(int argc, char *argv[], int expected_result) 363 { 364 int exit_code; 365 rtems_resource_snapshot snapshot, snapshot2; 366 367 exit_code = rtems_bsd_command_pfctl(argc, argv); 368 assert(exit_code == expected_result); 369 370 rtems_resource_snapshot_take(&snapshot); 371 exit_code = rtems_bsd_command_pfctl(argc, argv); 372 assert(exit_code == expected_result); 373 rtems_resource_snapshot_take(&snapshot2); 374 375 /* heap fragmentation might change so remove it from compare */ 376 snapshot.workspace_info.Free.largest = 0; 377 snapshot2.workspace_info.Free.largest = 0; 378 snapshot.heap_info.Free.largest = 0; 379 snapshot2.heap_info.Free.largest = 0; 380 assert(rtems_resource_snapshot_equal(&snapshot, &snapshot2)); 381 } 382 383 static void 384 test_pfctl(void) 385 { 386 char *no_params[] = { 387 "pfctl", 388 NULL 389 }; 390 char *invalid[] = { 391 "pfctl", 392 "-f", 393 TEST_CFG_INVALID, 394 "-q", 395 NULL 396 }; 397 char *block_most[] = { 398 "pfctl", 399 "-f", 400 TEST_CFG_BLOCK_MOST, 401 "-q", 402 NULL 403 }; 404 char *if_depend[] = { 405 "pfctl", 406 "-f", 407 TEST_CFG_IF_DEPEND, 408 "-q", 409 NULL 410 }; 411 412 puts("--- run pfctl with no paramters"); 413 run_pfctl(ARGC(no_params), no_params, EXIT_FAILURE); 414 415 puts("--- load invalid rule"); 416 run_pfctl(ARGC(invalid), invalid, EXIT_FAILURE); 417 418 puts("--- load rule to block input and most output"); 419 run_pfctl(ARGC(block_most), block_most, EXIT_SUCCESS); 420 421 puts("--- load rule to block if dependent"); 422 run_pfctl(ARGC(if_depend), if_depend, EXIT_SUCCESS); 423 } 424 425 static void 426 test_allow_lo1() 427 { 428 char *pfctl[] = { 429 "pfctl", 430 "-f", 431 TEST_CFG_ALLOW_LO1, 432 "-q", 433 NULL 434 }; 435 436 disable_pf(true); 437 438 puts("--- check services"); 439 check_services(LO1_IP, true, true); 440 check_services(LO2_IP, true, true); 441 442 puts("--- load and enable rule to allow only lo1"); 443 run_pfctl(ARGC(pfctl), pfctl, EXIT_SUCCESS); 444 enable_pf(); 445 446 puts("--- check services"); 447 check_services(LO1_IP, true, true); 448 check_services(LO2_IP, false, false); 449 } 450 451 static void 452 test_telnet_lo1() 453 { 454 char *pfctl[] = { 455 "pfctl", 456 "-f", 457 TEST_CFG_TELNET_LO1, 458 "-q", 459 NULL 460 }; 461 462 disable_pf(true); 463 464 puts("--- check services"); 465 check_services(LO1_IP, true, true); 466 check_services(LO2_IP, true, true); 467 468 puts("--- load and enable rule to allow telnet on lo1"); 469 run_pfctl(ARGC(pfctl), pfctl, EXIT_SUCCESS); 470 enable_pf(); 471 472 puts("--- check services"); 473 check_services(LO1_IP, true, false); 474 check_services(LO2_IP, false, false); 475 } 476 36 477 static void 37 478 test_main(void) 38 479 { 480 prepare_files(); 481 prepare_interfaces(); 482 prepare_services(); 483 484 test_pfctl(); 485 486 test_allow_lo1(); 487 test_telnet_lo1(); 488 39 489 exit(0); 40 490 }
Note: See TracChangeset
for help on using the changeset viewer.