functional.c (2aaf9152a852aba9eb2036b95f4948ee77988826) | functional.c (fdf929ff91d432d17c4d7d0aa0f9995fffe6fa8e) |
---|---|
1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2018 Alan Somers. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: --- 24 unchanged lines hidden (view full) --- 33#include <sys/stat.h> 34#include <sys/wait.h> 35 36#include <netinet/in.h> 37 38#include <errno.h> 39#include <fcntl.h> 40#include <signal.h> | 1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2018 Alan Somers. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: --- 24 unchanged lines hidden (view full) --- 33#include <sys/stat.h> 34#include <sys/wait.h> 35 36#include <netinet/in.h> 37 38#include <errno.h> 39#include <fcntl.h> 40#include <signal.h> |
41#include <stdalign.h> |
|
41#include <stdio.h> 42#include <unistd.h> 43 44#include <atf-c.h> 45#include <libutil.h> 46 47static const uint16_t BASEPORT = 6969; 48static const char pidfile[] = "tftpd.pid"; --- 35 unchanged lines hidden (view full) --- 84 85static void 86recv_ack(uint16_t blocknum) 87{ 88 char hdr[] = {0, 4, blocknum >> 8, blocknum & 0xFF}; 89 RECV(hdr, NULL, 0); 90} 91 | 42#include <stdio.h> 43#include <unistd.h> 44 45#include <atf-c.h> 46#include <libutil.h> 47 48static const uint16_t BASEPORT = 6969; 49static const char pidfile[] = "tftpd.pid"; --- 35 unchanged lines hidden (view full) --- 85 86static void 87recv_ack(uint16_t blocknum) 88{ 89 char hdr[] = {0, 4, blocknum >> 8, blocknum & 0xFF}; 90 RECV(hdr, NULL, 0); 91} 92 |
93static void 94recv_oack(const char *options, size_t options_len) 95{ 96 char hdr[] = {0, 6}; 97 RECV(hdr, options, options_len); 98} 99 |
|
92/* 93 * Receive a data packet from tftpd 94 * @param blocknum Expected block number to be received 95 * @param contents Pointer to expected contents 96 * @param contents_len Length of contents expected to receive 97 */ 98static void 99recv_data(uint16_t blocknum, const char* contents, size_t contents_len) --- 54 unchanged lines hidden (view full) --- 154 blocknum >> 8, 155 blocknum & 0xFF 156 }; 157 158 send_bytes(packet, sizeof(packet)); 159 160} 161 | 100/* 101 * Receive a data packet from tftpd 102 * @param blocknum Expected block number to be received 103 * @param contents Pointer to expected contents 104 * @param contents_len Length of contents expected to receive 105 */ 106static void 107recv_data(uint16_t blocknum, const char* contents, size_t contents_len) --- 54 unchanged lines hidden (view full) --- 162 blocknum >> 8, 163 blocknum & 0xFF 164 }; 165 166 send_bytes(packet, sizeof(packet)); 167 168} 169 |
170/* 171 * build an option string 172 */ 173#define OPTION_STR(name, value) name "\000" value "\000" 174 |
|
162/* 163 * send a read request to tftpd. 164 * @param filename filename as a string, absolute or relative 165 * @param mode either "octet" or "netascii" 166 */ 167#define SEND_RRQ(filename, mode) SEND_STR("\0\001" filename "\0" mode "\0") 168 | 175/* 176 * send a read request to tftpd. 177 * @param filename filename as a string, absolute or relative 178 * @param mode either "octet" or "netascii" 179 */ 180#define SEND_RRQ(filename, mode) SEND_STR("\0\001" filename "\0" mode "\0") 181 |
182/* 183 * send a read request with options 184 */ 185#define SEND_RRQ_OPT(filename, mode, options) SEND_STR("\0\001" filename "\0" mode "\000" options) 186 |
|
169/* 170 * send a write request to tftpd. 171 * @param filename filename as a string, absolute or relative 172 * @param mode either "octet" or "netascii" 173 */ 174#define SEND_WRQ(filename, mode) SEND_STR("\0\002" filename "\0" mode "\0") 175 | 187/* 188 * send a write request to tftpd. 189 * @param filename filename as a string, absolute or relative 190 * @param mode either "octet" or "netascii" 191 */ 192#define SEND_WRQ(filename, mode) SEND_STR("\0\002" filename "\0" mode "\0") 193 |
194/* 195 * send a write request with options 196 */ 197#define SEND_WRQ_OPT(filename, mode, options) SEND_STR("\0\002" filename "\0" mode "\000" options) 198 |
|
176/* Define a test case, for both IPv4 and IPv6 */ 177#define TFTPD_TC_DEFINE(name, head, ...) \ 178static void \ 179name ## _body(void); \ 180ATF_TC_WITH_CLEANUP(name ## _v4); \ 181ATF_TC_HEAD(name ## _v4, tc) \ 182{ \ 183 head \ --- 384 unchanged lines hidden (view full) --- 568 SEND_RRQ("medium.txt", "octet"); 569 recv_data(1, (const char*)&contents[0], 512); 570 send_ack(1); 571 recv_data(2, (const char*)&contents[128], 256); 572 send_ack(2); 573} 574 575/* | 199/* Define a test case, for both IPv4 and IPv6 */ 200#define TFTPD_TC_DEFINE(name, head, ...) \ 201static void \ 202name ## _body(void); \ 203ATF_TC_WITH_CLEANUP(name ## _v4); \ 204ATF_TC_HEAD(name ## _v4, tc) \ 205{ \ 206 head \ --- 384 unchanged lines hidden (view full) --- 591 SEND_RRQ("medium.txt", "octet"); 592 recv_data(1, (const char*)&contents[0], 512); 593 send_ack(1); 594 recv_data(2, (const char*)&contents[128], 256); 595 send_ack(2); 596} 597 598/* |
599 * Read a medium file with a window size of 2. 600 */ 601TFTPD_TC_DEFINE(rrq_medium_window,) 602{ 603 int fd; 604 size_t i; 605 uint32_t contents[192]; 606 char options[] = OPTION_STR("windowsize", "2"); 607 608 for (i = 0; i < nitems(contents); i++) 609 contents[i] = i; 610 611 fd = open("medium.txt", O_RDWR | O_CREAT, 0644); 612 ATF_REQUIRE(fd >= 0); 613 write_all(fd, contents, sizeof(contents)); 614 close(fd); 615 616 SEND_RRQ_OPT("medium.txt", "octet", OPTION_STR("windowsize", "2")); 617 recv_oack(options, sizeof(options) - 1); 618 send_ack(0); 619 recv_data(1, (const char*)&contents[0], 512); 620 recv_data(2, (const char*)&contents[128], 256); 621 send_ack(2); 622} 623 624/* |
|
576 * Read a file in netascii format 577 */ 578TFTPD_TC_DEFINE(rrq_netascii,) 579{ 580 int fd; 581 char contents[] = "foo\nbar\rbaz\n"; 582 /* 583 * Weirdly, RFC-764 says that CR must be followed by NUL if a line feed --- 63 unchanged lines hidden (view full) --- 647 close(fd); 648 649 SEND_RRQ("small.txt", "octet"); 650 recv_data(1, contents, strlen(contents) + 1); 651 send_ack(1); 652} 653 654/* | 625 * Read a file in netascii format 626 */ 627TFTPD_TC_DEFINE(rrq_netascii,) 628{ 629 int fd; 630 char contents[] = "foo\nbar\rbaz\n"; 631 /* 632 * Weirdly, RFC-764 says that CR must be followed by NUL if a line feed --- 63 unchanged lines hidden (view full) --- 696 close(fd); 697 698 SEND_RRQ("small.txt", "octet"); 699 recv_data(1, contents, strlen(contents) + 1); 700 send_ack(1); 701} 702 703/* |
704 * Read a file following the example in RFC 7440. 705 */ 706TFTPD_TC_DEFINE(rrq_window_rfc7440,) 707{ 708 int fd; 709 size_t i; 710 char options[] = OPTION_STR("windowsize", "4"); 711 alignas(uint32_t) char contents[13 * 512 - 4]; 712 uint32_t *u32p; 713 714 u32p = (uint32_t *)contents; 715 for (i = 0; i < sizeof(contents) / sizeof(uint32_t); i++) 716 u32p[i] = i; 717 718 fd = open("rfc7440.txt", O_RDWR | O_CREAT, 0644); 719 ATF_REQUIRE(fd >= 0); 720 write_all(fd, contents, sizeof(contents)); 721 close(fd); 722 723 SEND_RRQ_OPT("rfc7440.txt", "octet", OPTION_STR("windowsize", "4")); 724 recv_oack(options, sizeof(options) - 1); 725 send_ack(0); 726 recv_data(1, &contents[0 * 512], 512); 727 recv_data(2, &contents[1 * 512], 512); 728 recv_data(3, &contents[2 * 512], 512); 729 recv_data(4, &contents[3 * 512], 512); 730 send_ack(4); 731 recv_data(5, &contents[4 * 512], 512); 732 recv_data(6, &contents[5 * 512], 512); 733 recv_data(7, &contents[6 * 512], 512); 734 recv_data(8, &contents[7 * 512], 512); 735 736 /* ACK 5 as if 6-8 were dropped. */ 737 send_ack(5); 738 recv_data(6, &contents[5 * 512], 512); 739 recv_data(7, &contents[6 * 512], 512); 740 recv_data(8, &contents[7 * 512], 512); 741 recv_data(9, &contents[8 * 512], 512); 742 send_ack(9); 743 recv_data(10, &contents[9 * 512], 512); 744 recv_data(11, &contents[10 * 512], 512); 745 recv_data(12, &contents[11 * 512], 512); 746 recv_data(13, &contents[12 * 512], 508); 747 748 /* Drop ACK and after timeout receive 10-13. */ 749 recv_data(10, &contents[9 * 512], 512); 750 recv_data(11, &contents[10 * 512], 512); 751 recv_data(12, &contents[11 * 512], 512); 752 recv_data(13, &contents[12 * 512], 508); 753 send_ack(13); 754} 755 756/* |
|
655 * Try to transfer a file with an unknown mode. 656 */ 657TFTPD_TC_DEFINE(unknown_modes,) 658{ 659 SEND_RRQ("foo.txt", "ascii"); /* Misspelling of "ascii" */ 660 RECV_ERROR(4, "Illegal TFTP operation"); 661 s = setup(&addr, __COUNTER__); \ 662 SEND_RRQ("foo.txt", "binary"); /* Obsolete. Use "octet" instead */ --- 204 unchanged lines hidden (view full) --- 867 fd = open("medium.txt", O_RDONLY); 868 ATF_REQUIRE(fd >= 0); 869 r = read(fd, buffer, sizeof(buffer)); 870 close(fd); 871 require_bufeq((const char*)contents, 768, buffer, r); 872} 873 874/* | 757 * Try to transfer a file with an unknown mode. 758 */ 759TFTPD_TC_DEFINE(unknown_modes,) 760{ 761 SEND_RRQ("foo.txt", "ascii"); /* Misspelling of "ascii" */ 762 RECV_ERROR(4, "Illegal TFTP operation"); 763 s = setup(&addr, __COUNTER__); \ 764 SEND_RRQ("foo.txt", "binary"); /* Obsolete. Use "octet" instead */ --- 204 unchanged lines hidden (view full) --- 969 fd = open("medium.txt", O_RDONLY); 970 ATF_REQUIRE(fd >= 0); 971 r = read(fd, buffer, sizeof(buffer)); 972 close(fd); 973 require_bufeq((const char*)contents, 768, buffer, r); 974} 975 976/* |
977 * Write a medium file with a window size of 2. 978 */ 979TFTPD_TC_DEFINE(wrq_medium_window,) 980{ 981 int fd; 982 size_t i; 983 ssize_t r; 984 uint32_t contents[192]; 985 char buffer[1024]; 986 char options[] = OPTION_STR("windowsize", "2"); 987 988 for (i = 0; i < nitems(contents); i++) 989 contents[i] = i; 990 991 fd = open("medium.txt", O_RDWR | O_CREAT, 0666); 992 ATF_REQUIRE(fd >= 0); 993 close(fd); 994 995 SEND_WRQ_OPT("medium.txt", "octet", OPTION_STR("windowsize", "2")); 996 recv_oack(options, sizeof(options) - 1); 997 send_data(1, (const char*)&contents[0], 512); 998 send_data(2, (const char*)&contents[128], 256); 999 recv_ack(2); 1000 1001 fd = open("medium.txt", O_RDONLY); 1002 ATF_REQUIRE(fd >= 0); 1003 r = read(fd, buffer, sizeof(buffer)); 1004 close(fd); 1005 require_bufeq((const char*)contents, 768, buffer, r); 1006} 1007 1008/* |
|
875 * Write a file in netascii format 876 */ 877TFTPD_TC_DEFINE(wrq_netascii,) 878{ 879 int fd; 880 ssize_t r; 881 /* 882 * Weirdly, RFC-764 says that CR must be followed by NUL if a line feed --- 77 unchanged lines hidden (view full) --- 960 recv_ack(0); 961 send_data(1, NULL, 0); 962 recv_ack(1); 963 964 ATF_REQUIRE_EQ(stat("small.txt", &sb), 0); 965 ATF_REQUIRE_EQ(sb.st_size, 0); 966} 967 | 1009 * Write a file in netascii format 1010 */ 1011TFTPD_TC_DEFINE(wrq_netascii,) 1012{ 1013 int fd; 1014 ssize_t r; 1015 /* 1016 * Weirdly, RFC-764 says that CR must be followed by NUL if a line feed --- 77 unchanged lines hidden (view full) --- 1094 recv_ack(0); 1095 send_data(1, NULL, 0); 1096 recv_ack(1); 1097 1098 ATF_REQUIRE_EQ(stat("small.txt", &sb), 0); 1099 ATF_REQUIRE_EQ(sb.st_size, 0); 1100} 1101 |
1102/* 1103 * Write a file following the example in RFC 7440. 1104 */ 1105TFTPD_TC_DEFINE(wrq_window_rfc7440,) 1106{ 1107 int fd; 1108 size_t i; 1109 ssize_t r; 1110 char options[] = OPTION_STR("windowsize", "4"); 1111 alignas(uint32_t) char contents[13 * 512 - 4]; 1112 char buffer[sizeof(contents)]; 1113 uint32_t *u32p; |
|
968 | 1114 |
1115 u32p = (uint32_t *)contents; 1116 for (i = 0; i < sizeof(contents) / sizeof(uint32_t); i++) 1117 u32p[i] = i; 1118 1119 fd = open("rfc7440.txt", O_RDWR | O_CREAT, 0666); 1120 ATF_REQUIRE(fd >= 0); 1121 close(fd); 1122 1123 SEND_WRQ_OPT("rfc7440.txt", "octet", OPTION_STR("windowsize", "4")); 1124 recv_oack(options, sizeof(options) - 1); 1125 send_data(1, &contents[0 * 512], 512); 1126 send_data(2, &contents[1 * 512], 512); 1127 send_data(3, &contents[2 * 512], 512); 1128 send_data(4, &contents[3 * 512], 512); 1129 recv_ack(4); 1130 send_data(5, &contents[4 * 512], 512); 1131 1132 /* Drop 6-8. */ 1133 recv_ack(5); 1134 send_data(6, &contents[5 * 512], 512); 1135 send_data(7, &contents[6 * 512], 512); 1136 send_data(8, &contents[7 * 512], 512); 1137 send_data(9, &contents[8 * 512], 512); 1138 recv_ack(9); 1139 1140 /* Drop 11. */ 1141 send_data(10, &contents[9 * 512], 512); 1142 send_data(12, &contents[11 * 512], 512); 1143 1144 /* 1145 * We can't send 13 here as tftpd has probably already seen 12 1146 * and sent the ACK of 10 if running locally. While it would 1147 * recover by sending another ACK of 10, our state machine 1148 * would be out of sync. 1149 */ 1150 1151 /* Ignore ACK for 10 and resend 10-13. */ 1152 recv_ack(10); 1153 send_data(10, &contents[9 * 512], 512); 1154 send_data(11, &contents[10 * 512], 512); 1155 send_data(12, &contents[11 * 512], 512); 1156 send_data(13, &contents[12 * 512], 508); 1157 recv_ack(13); 1158 1159 fd = open("rfc7440.txt", O_RDONLY); 1160 ATF_REQUIRE(fd >= 0); 1161 r = read(fd, buffer, sizeof(buffer)); 1162 close(fd); 1163 require_bufeq(contents, sizeof(contents), buffer, r); 1164} 1165 1166 |
|
969/* 970 * Main 971 */ 972 973ATF_TP_ADD_TCS(tp) 974{ 975 TFTPD_TC_ADD(tp, abspath); 976 TFTPD_TC_ADD(tp, dotdot); 977 TFTPD_TC_ADD(tp, s_flag); 978 TFTPD_TC_ADD(tp, rrq_dropped_ack); 979 TFTPD_TC_ADD(tp, rrq_dropped_data); 980 TFTPD_TC_ADD(tp, rrq_duped_ack); 981 TFTPD_TC_ADD(tp, rrq_eaccess); 982 TFTPD_TC_ADD(tp, rrq_empty); 983 TFTPD_TC_ADD(tp, rrq_medium); | 1167/* 1168 * Main 1169 */ 1170 1171ATF_TP_ADD_TCS(tp) 1172{ 1173 TFTPD_TC_ADD(tp, abspath); 1174 TFTPD_TC_ADD(tp, dotdot); 1175 TFTPD_TC_ADD(tp, s_flag); 1176 TFTPD_TC_ADD(tp, rrq_dropped_ack); 1177 TFTPD_TC_ADD(tp, rrq_dropped_data); 1178 TFTPD_TC_ADD(tp, rrq_duped_ack); 1179 TFTPD_TC_ADD(tp, rrq_eaccess); 1180 TFTPD_TC_ADD(tp, rrq_empty); 1181 TFTPD_TC_ADD(tp, rrq_medium); |
1182 TFTPD_TC_ADD(tp, rrq_medium_window); |
|
984 TFTPD_TC_ADD(tp, rrq_netascii); 985 TFTPD_TC_ADD(tp, rrq_nonexistent); 986 TFTPD_TC_ADD(tp, rrq_path_max); 987 TFTPD_TC_ADD(tp, rrq_small); | 1183 TFTPD_TC_ADD(tp, rrq_netascii); 1184 TFTPD_TC_ADD(tp, rrq_nonexistent); 1185 TFTPD_TC_ADD(tp, rrq_path_max); 1186 TFTPD_TC_ADD(tp, rrq_small); |
1187 TFTPD_TC_ADD(tp, rrq_window_rfc7440); |
|
988 TFTPD_TC_ADD(tp, unknown_modes); 989 TFTPD_TC_ADD(tp, unknown_opcode); 990 TFTPD_TC_ADD(tp, w_flag); 991 TFTPD_TC_ADD(tp, wrq_dropped_ack); 992 TFTPD_TC_ADD(tp, wrq_dropped_data); 993 TFTPD_TC_ADD(tp, wrq_duped_data); 994 TFTPD_TC_ADD(tp, wrq_eaccess); 995 TFTPD_TC_ADD(tp, wrq_eaccess_world_readable); 996 TFTPD_TC_ADD(tp, wrq_medium); | 1188 TFTPD_TC_ADD(tp, unknown_modes); 1189 TFTPD_TC_ADD(tp, unknown_opcode); 1190 TFTPD_TC_ADD(tp, w_flag); 1191 TFTPD_TC_ADD(tp, wrq_dropped_ack); 1192 TFTPD_TC_ADD(tp, wrq_dropped_data); 1193 TFTPD_TC_ADD(tp, wrq_duped_data); 1194 TFTPD_TC_ADD(tp, wrq_eaccess); 1195 TFTPD_TC_ADD(tp, wrq_eaccess_world_readable); 1196 TFTPD_TC_ADD(tp, wrq_medium); |
1197 TFTPD_TC_ADD(tp, wrq_medium_window); |
|
997 TFTPD_TC_ADD(tp, wrq_netascii); 998 TFTPD_TC_ADD(tp, wrq_nonexistent); 999 TFTPD_TC_ADD(tp, wrq_small); 1000 TFTPD_TC_ADD(tp, wrq_truncate); | 1198 TFTPD_TC_ADD(tp, wrq_netascii); 1199 TFTPD_TC_ADD(tp, wrq_nonexistent); 1200 TFTPD_TC_ADD(tp, wrq_small); 1201 TFTPD_TC_ADD(tp, wrq_truncate); |
1202 TFTPD_TC_ADD(tp, wrq_window_rfc7440); |
|
1001 1002 return (atf_no_error()); 1003} | 1203 1204 return (atf_no_error()); 1205} |