LCOV - code coverage report
Current view: top level - libsystemd-network - test-dhcp-option.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 167 198 84.3 %
Date: 2019-08-22 15:41:25 Functions: 8 9 88.9 %

          Line data    Source code
       1             : #include <errno.h>
       2             : #include <stdbool.h>
       3             : #include <stdio.h>
       4             : #include <string.h>
       5             : 
       6             : #include "alloc-util.h"
       7             : #include "dhcp-internal.h"
       8             : #include "dhcp-protocol.h"
       9             : #include "macro.h"
      10             : #include "memory-util.h"
      11             : 
      12             : struct option_desc {
      13             :         uint8_t sname[64];
      14             :         int snamelen;
      15             :         uint8_t file[128];
      16             :         int filelen;
      17             :         uint8_t options[128];
      18             :         int len;
      19             :         bool success;
      20             :         int filepos;
      21             :         int snamepos;
      22             :         int pos;
      23             : };
      24             : 
      25             : static bool verbose = false;
      26             : 
      27             : static struct option_desc option_tests[] = {
      28             :         { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69 }, 7, false, },
      29             :         { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69, 0, 0,
      30             :                           SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 12, true, },
      31             :         { {}, 0, {}, 0, { 8, 255, 70, 71, 72 }, 5, false, },
      32             :         { {}, 0, {}, 0, { 0x35, 0x01, 0x05, 0x36, 0x04, 0x01, 0x00, 0xa8,
      33             :                           0xc0, 0x33, 0x04, 0x00, 0x01, 0x51, 0x80, 0x01,
      34             :                           0x04, 0xff, 0xff, 0xff, 0x00, 0x03, 0x04, 0xc0,
      35             :                           0xa8, 0x00, 0x01, 0x06, 0x04, 0xc0, 0xa8, 0x00,
      36             :                           0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
      37             :           40, true, },
      38             :         { {}, 0, {}, 0, { SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_OFFER,
      39             :                           42, 3, 0, 0, 0 }, 8, true, },
      40             :         { {}, 0, {}, 0, { 42, 2, 1, 2, 44 }, 5, false, },
      41             : 
      42             :         { {}, 0,
      43             :           { 222, 3, 1, 2, 3, SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_NAK }, 8,
      44             :           { SD_DHCP_OPTION_OVERLOAD, 1, DHCP_OVERLOAD_FILE }, 3, true, },
      45             : 
      46             :         { { 1, 4, 1, 2, 3, 4, SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 9,
      47             :           { 222, 3, 1, 2, 3 }, 5,
      48             :           { SD_DHCP_OPTION_OVERLOAD, 1,
      49             :             DHCP_OVERLOAD_FILE|DHCP_OVERLOAD_SNAME }, 3, true, },
      50             : };
      51             : 
      52           0 : static const char *dhcp_type(int type) {
      53           0 :         switch(type) {
      54           0 :         case DHCP_DISCOVER:
      55           0 :                 return "DHCPDISCOVER";
      56           0 :         case DHCP_OFFER:
      57           0 :                 return "DHCPOFFER";
      58           0 :         case DHCP_REQUEST:
      59           0 :                 return "DHCPREQUEST";
      60           0 :         case DHCP_DECLINE:
      61           0 :                 return "DHCPDECLINE";
      62           0 :         case DHCP_ACK:
      63           0 :                 return "DHCPACK";
      64           0 :         case DHCP_NAK:
      65           0 :                 return "DHCPNAK";
      66           0 :         case DHCP_RELEASE:
      67           0 :                 return "DHCPRELEASE";
      68           0 :         default:
      69           0 :                 return "unknown";
      70             :         }
      71             : }
      72             : 
      73           1 : static void test_invalid_buffer_length(void) {
      74             :         DHCPMessage message;
      75             : 
      76           1 :         assert_se(dhcp_option_parse(&message, 0, NULL, NULL, NULL) == -EINVAL);
      77           1 :         assert_se(dhcp_option_parse(&message, sizeof(DHCPMessage) - 1, NULL, NULL, NULL) == -EINVAL);
      78           1 : }
      79             : 
      80           1 : static void test_message_init(void) {
      81           1 :         _cleanup_free_ DHCPMessage *message = NULL;
      82           1 :         size_t optlen = 4, optoffset;
      83           1 :         size_t len = sizeof(DHCPMessage) + optlen;
      84             :         uint8_t *magic;
      85             : 
      86           1 :         message = malloc0(len);
      87             : 
      88           1 :         assert_se(dhcp_message_init(message, BOOTREQUEST, 0x12345678,
      89             :                   DHCP_DISCOVER, ARPHRD_ETHER, optlen, &optoffset) >= 0);
      90             : 
      91           1 :         assert_se(message->xid == htobe32(0x12345678));
      92           1 :         assert_se(message->op == BOOTREQUEST);
      93             : 
      94           1 :         magic = (uint8_t*)&message->magic;
      95             : 
      96           1 :         assert_se(magic[0] == 99);
      97           1 :         assert_se(magic[1] == 130);
      98           1 :         assert_se(magic[2] == 83);
      99           1 :         assert_se(magic[3] == 99);
     100             : 
     101           1 :         assert_se(dhcp_option_parse(message, len, NULL, NULL, NULL) >= 0);
     102           1 : }
     103             : 
     104           9 : static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
     105             :                 uint8_t *file, uint8_t filelen,
     106             :                 uint8_t *sname, uint8_t snamelen) {
     107             :         DHCPMessage *message;
     108           9 :         size_t len = sizeof(DHCPMessage) + optlen;
     109             : 
     110           9 :         message = malloc0(len);
     111           9 :         assert_se(message);
     112             : 
     113           9 :         memcpy_safe(&message->options, options, optlen);
     114           9 :         memcpy_safe(&message->file, file, filelen);
     115           9 :         memcpy_safe(&message->sname, sname, snamelen);
     116             : 
     117           9 :         return message;
     118             : }
     119             : 
     120          26 : static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen) {
     121          26 :         assert(*descpos >= 0);
     122             : 
     123          42 :         while (*descpos < *desclen) {
     124          33 :                 switch(descoption[*descpos]) {
     125           9 :                 case SD_DHCP_OPTION_PAD:
     126           9 :                         *descpos += 1;
     127           9 :                         break;
     128             : 
     129           7 :                 case SD_DHCP_OPTION_MESSAGE_TYPE:
     130             :                 case SD_DHCP_OPTION_OVERLOAD:
     131           7 :                         *descpos += 3;
     132           7 :                         break;
     133             : 
     134          17 :                 default:
     135          17 :                         return;
     136             :                 }
     137             :         }
     138             : }
     139             : 
     140          12 : static int test_options_cb(uint8_t code, uint8_t len, const void *option, void *userdata) {
     141          12 :         struct option_desc *desc = userdata;
     142          12 :         uint8_t *descoption = NULL;
     143          12 :         int *desclen = NULL, *descpos = NULL;
     144          12 :         uint8_t optcode = 0;
     145          12 :         uint8_t optlen = 0;
     146             :         uint8_t i;
     147             : 
     148          12 :         assert_se((!desc && !code && !len) || desc);
     149             : 
     150          12 :         if (!desc)
     151           0 :                 return -EINVAL;
     152             : 
     153          12 :         assert_se(code != SD_DHCP_OPTION_PAD);
     154          12 :         assert_se(code != SD_DHCP_OPTION_END);
     155          12 :         assert_se(code != SD_DHCP_OPTION_MESSAGE_TYPE);
     156          12 :         assert_se(code != SD_DHCP_OPTION_OVERLOAD);
     157             : 
     158          14 :         while (desc->pos >= 0 || desc->filepos >= 0 || desc->snamepos >= 0) {
     159             : 
     160          14 :                 if (desc->pos >= 0) {
     161          11 :                         descoption = &desc->options[0];
     162          11 :                         desclen = &desc->len;
     163          11 :                         descpos = &desc->pos;
     164           3 :                 } else if (desc->filepos >= 0) {
     165           2 :                         descoption = &desc->file[0];
     166           2 :                         desclen = &desc->filelen;
     167           2 :                         descpos = &desc->filepos;
     168           1 :                 } else if (desc->snamepos >= 0) {
     169           1 :                         descoption = &desc->sname[0];
     170           1 :                         desclen = &desc->snamelen;
     171           1 :                         descpos = &desc->snamepos;
     172             :                 }
     173             : 
     174          14 :                 assert_se(descoption && desclen && descpos);
     175             : 
     176          14 :                 if (*desclen)
     177          14 :                         test_ignore_opts(descoption, descpos, desclen);
     178             : 
     179          14 :                 if (*descpos < *desclen)
     180          12 :                         break;
     181             : 
     182           2 :                 if (*descpos == *desclen)
     183           2 :                         *descpos = -1;
     184             :         }
     185             : 
     186          12 :         assert_se(descpos);
     187          12 :         assert_se(*descpos != -1);
     188             : 
     189          12 :         optcode = descoption[*descpos];
     190          12 :         optlen = descoption[*descpos + 1];
     191             : 
     192          12 :         if (verbose)
     193           0 :                 printf("DHCP code %2d(%2d) len %2d(%2d) ", code, optcode,
     194             :                                 len, optlen);
     195             : 
     196          12 :         assert_se(code == optcode);
     197          12 :         assert_se(len == optlen);
     198             : 
     199          57 :         for (i = 0; i < len; i++) {
     200             : 
     201          45 :                 if (verbose)
     202           0 :                         printf("0x%02x(0x%02x) ", ((uint8_t*) option)[i],
     203           0 :                                         descoption[*descpos + 2 + i]);
     204             : 
     205          45 :                 assert_se(((uint8_t*) option)[i] == descoption[*descpos + 2 + i]);
     206             :         }
     207             : 
     208          12 :         if (verbose)
     209           0 :                 printf("\n");
     210             : 
     211          12 :         *descpos += optlen + 2;
     212             : 
     213          12 :         test_ignore_opts(descoption, descpos, desclen);
     214             : 
     215          12 :         if (desc->pos != -1 && desc->pos == desc->len)
     216           4 :                 desc->pos = -1;
     217             : 
     218          12 :         if (desc->filepos != -1 && desc->filepos == desc->filelen)
     219           2 :                 desc->filepos = -1;
     220             : 
     221          12 :         if (desc->snamepos != -1 && desc->snamepos == desc->snamelen)
     222           1 :                 desc->snamepos = -1;
     223             : 
     224          12 :         return 0;
     225             : }
     226             : 
     227           9 : static void test_options(struct option_desc *desc) {
     228           9 :         uint8_t *options = NULL;
     229           9 :         uint8_t *file = NULL;
     230           9 :         uint8_t *sname = NULL;
     231           9 :         int optlen = 0;
     232           9 :         int filelen = 0;
     233           9 :         int snamelen = 0;
     234           9 :         int buflen = 0;
     235           9 :         _cleanup_free_ DHCPMessage *message = NULL;
     236             :         int res;
     237             : 
     238           9 :         if (desc) {
     239           8 :                 file = &desc->file[0];
     240           8 :                 filelen = desc->filelen;
     241           8 :                 if (!filelen)
     242           6 :                         desc->filepos = -1;
     243             : 
     244           8 :                 sname = &desc->sname[0];
     245           8 :                 snamelen = desc->snamelen;
     246           8 :                 if (!snamelen)
     247           7 :                         desc->snamepos = -1;
     248             : 
     249           8 :                 options = &desc->options[0];
     250           8 :                 optlen = desc->len;
     251           8 :                 desc->pos = 0;
     252             :         }
     253           9 :         message = create_message(options, optlen, file, filelen,
     254             :                                  sname, snamelen);
     255             : 
     256           9 :         buflen = sizeof(DHCPMessage) + optlen;
     257             : 
     258           9 :         if (!desc) {
     259           1 :                 assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, NULL, NULL)) == -ENOMSG);
     260           8 :         } else if (desc->success) {
     261           5 :                 assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) >= 0);
     262           5 :                 assert_se(desc->pos == -1 && desc->filepos == -1 && desc->snamepos == -1);
     263             :         } else
     264           3 :                 assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) < 0);
     265             : 
     266           9 :         if (verbose)
     267           0 :                 printf("DHCP type %s\n", dhcp_type(res));
     268           9 : }
     269             : 
     270             : static uint8_t options[64] = {
     271             :         'A', 'B', 'C', 'D',
     272             :         160, 2, 0x11, 0x12,
     273             :         0,
     274             :         31, 8, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
     275             :         0,
     276             :         55, 3, 0x51, 0x52, 0x53,
     277             :         17, 7, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
     278             :         255
     279             : };
     280             : 
     281           1 : static void test_option_set(void) {
     282           1 :         _cleanup_free_ DHCPMessage *result = NULL;
     283           1 :         size_t offset = 0, len, pos;
     284             :         unsigned i;
     285             : 
     286           1 :         result = malloc0(sizeof(DHCPMessage) + 11);
     287           1 :         assert_se(result);
     288             : 
     289           1 :         result->options[0] = 'A';
     290           1 :         result->options[1] = 'B';
     291           1 :         result->options[2] = 'C';
     292           1 :         result->options[3] = 'D';
     293             : 
     294           1 :         assert_se(dhcp_option_append(result, 0, &offset, 0, SD_DHCP_OPTION_PAD,
     295             :                                      0, NULL) == -ENOBUFS);
     296           1 :         assert_se(offset == 0);
     297             : 
     298           1 :         offset = 4;
     299           1 :         assert_se(dhcp_option_append(result, 5, &offset, 0, SD_DHCP_OPTION_PAD,
     300             :                                      0, NULL) == -ENOBUFS);
     301           1 :         assert_se(offset == 4);
     302           1 :         assert_se(dhcp_option_append(result, 6, &offset, 0, SD_DHCP_OPTION_PAD,
     303             :                                      0, NULL) >= 0);
     304           1 :         assert_se(offset == 5);
     305             : 
     306           1 :         offset = pos = 4;
     307           1 :         len = 11;
     308           4 :         while (pos < len && options[pos] != SD_DHCP_OPTION_END) {
     309           3 :                 assert_se(dhcp_option_append(result, len, &offset, DHCP_OVERLOAD_SNAME,
     310             :                                              options[pos],
     311             :                                              options[pos + 1],
     312             :                                              &options[pos + 2]) >= 0);
     313             : 
     314           3 :                 if (options[pos] == SD_DHCP_OPTION_PAD)
     315           1 :                         pos++;
     316             :                 else
     317           2 :                         pos += 2 + options[pos + 1];
     318             : 
     319           3 :                 if (pos < len)
     320           2 :                         assert_se(offset == pos);
     321             :         }
     322             : 
     323          10 :         for (i = 0; i < 9; i++) {
     324           9 :                 if (verbose)
     325           0 :                         printf("%2u: 0x%02x(0x%02x) (options)\n", i, result->options[i],
     326           0 :                                options[i]);
     327           9 :                 assert_se(result->options[i] == options[i]);
     328             :         }
     329             : 
     330           1 :         if (verbose)
     331           0 :                 printf("%2d: 0x%02x(0x%02x) (options)\n", 9, result->options[9],
     332             :                        SD_DHCP_OPTION_END);
     333             : 
     334           1 :         assert_se(result->options[9] == SD_DHCP_OPTION_END);
     335             : 
     336           1 :         if (verbose)
     337           0 :                 printf("%2d: 0x%02x(0x%02x) (options)\n", 10, result->options[10],
     338             :                        SD_DHCP_OPTION_PAD);
     339             : 
     340           1 :         assert_se(result->options[10] == SD_DHCP_OPTION_PAD);
     341             : 
     342          12 :         for (i = 0; i < pos - 8; i++) {
     343          11 :                 if (verbose)
     344           0 :                         printf("%2u: 0x%02x(0x%02x) (sname)\n", i, result->sname[i],
     345           0 :                                options[i + 9]);
     346          11 :                 assert_se(result->sname[i] == options[i + 9]);
     347             :         }
     348             : 
     349           1 :         if (verbose)
     350           0 :                 printf ("\n");
     351           1 : }
     352             : 
     353           1 : int main(int argc, char *argv[]) {
     354             :         unsigned i;
     355             : 
     356           1 :         test_invalid_buffer_length();
     357           1 :         test_message_init();
     358             : 
     359           1 :         test_options(NULL);
     360             : 
     361           9 :         for (i = 0; i < ELEMENTSOF(option_tests); i++)
     362           8 :                 test_options(&option_tests[i]);
     363             : 
     364           1 :         test_option_set();
     365             : 
     366           1 :         return 0;
     367             : }

Generated by: LCOV version 1.14