LCOV - code coverage report
Current view: top level - libsystemd-network - test-dhcp-option.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 167 198 84.3 %
Date: 2019-08-23 13:36:53 Functions: 8 9 88.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 114 191 59.7 %

           Branch data     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                 :          4 : static void test_invalid_buffer_length(void) {
      74                 :            :         DHCPMessage message;
      75                 :            : 
      76         [ -  + ]:          4 :         assert_se(dhcp_option_parse(&message, 0, NULL, NULL, NULL) == -EINVAL);
      77         [ -  + ]:          4 :         assert_se(dhcp_option_parse(&message, sizeof(DHCPMessage) - 1, NULL, NULL, NULL) == -EINVAL);
      78                 :          4 : }
      79                 :            : 
      80                 :          4 : static void test_message_init(void) {
      81                 :          4 :         _cleanup_free_ DHCPMessage *message = NULL;
      82                 :          4 :         size_t optlen = 4, optoffset;
      83                 :          4 :         size_t len = sizeof(DHCPMessage) + optlen;
      84                 :            :         uint8_t *magic;
      85                 :            : 
      86                 :          4 :         message = malloc0(len);
      87                 :            : 
      88         [ -  + ]:          4 :         assert_se(dhcp_message_init(message, BOOTREQUEST, 0x12345678,
      89                 :            :                   DHCP_DISCOVER, ARPHRD_ETHER, optlen, &optoffset) >= 0);
      90                 :            : 
      91         [ -  + ]:          4 :         assert_se(message->xid == htobe32(0x12345678));
      92         [ -  + ]:          4 :         assert_se(message->op == BOOTREQUEST);
      93                 :            : 
      94                 :          4 :         magic = (uint8_t*)&message->magic;
      95                 :            : 
      96         [ -  + ]:          4 :         assert_se(magic[0] == 99);
      97         [ -  + ]:          4 :         assert_se(magic[1] == 130);
      98         [ -  + ]:          4 :         assert_se(magic[2] == 83);
      99         [ -  + ]:          4 :         assert_se(magic[3] == 99);
     100                 :            : 
     101         [ -  + ]:          4 :         assert_se(dhcp_option_parse(message, len, NULL, NULL, NULL) >= 0);
     102                 :          4 : }
     103                 :            : 
     104                 :         36 : 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                 :         36 :         size_t len = sizeof(DHCPMessage) + optlen;
     109                 :            : 
     110                 :         36 :         message = malloc0(len);
     111         [ -  + ]:         36 :         assert_se(message);
     112                 :            : 
     113                 :         36 :         memcpy_safe(&message->options, options, optlen);
     114                 :         36 :         memcpy_safe(&message->file, file, filelen);
     115                 :         36 :         memcpy_safe(&message->sname, sname, snamelen);
     116                 :            : 
     117                 :         36 :         return message;
     118                 :            : }
     119                 :            : 
     120                 :        104 : static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen) {
     121         [ -  + ]:        104 :         assert(*descpos >= 0);
     122                 :            : 
     123         [ +  + ]:        168 :         while (*descpos < *desclen) {
     124      [ +  +  + ]:        132 :                 switch(descoption[*descpos]) {
     125                 :         36 :                 case SD_DHCP_OPTION_PAD:
     126                 :         36 :                         *descpos += 1;
     127                 :         36 :                         break;
     128                 :            : 
     129                 :         28 :                 case SD_DHCP_OPTION_MESSAGE_TYPE:
     130                 :            :                 case SD_DHCP_OPTION_OVERLOAD:
     131                 :         28 :                         *descpos += 3;
     132                 :         28 :                         break;
     133                 :            : 
     134                 :         68 :                 default:
     135                 :         68 :                         return;
     136                 :            :                 }
     137                 :            :         }
     138                 :            : }
     139                 :            : 
     140                 :         48 : static int test_options_cb(uint8_t code, uint8_t len, const void *option, void *userdata) {
     141                 :         48 :         struct option_desc *desc = userdata;
     142                 :         48 :         uint8_t *descoption = NULL;
     143                 :         48 :         int *desclen = NULL, *descpos = NULL;
     144                 :         48 :         uint8_t optcode = 0;
     145                 :         48 :         uint8_t optlen = 0;
     146                 :            :         uint8_t i;
     147                 :            : 
     148   [ -  +  #  #  :         48 :         assert_se((!desc && !code && !len) || desc);
          -  +  #  #  +  
                -  -  + ]
     149                 :            : 
     150         [ -  + ]:         48 :         if (!desc)
     151                 :          0 :                 return -EINVAL;
     152                 :            : 
     153         [ -  + ]:         48 :         assert_se(code != SD_DHCP_OPTION_PAD);
     154         [ -  + ]:         48 :         assert_se(code != SD_DHCP_OPTION_END);
     155         [ -  + ]:         48 :         assert_se(code != SD_DHCP_OPTION_MESSAGE_TYPE);
     156         [ -  + ]:         48 :         assert_se(code != SD_DHCP_OPTION_OVERLOAD);
     157                 :            : 
     158   [ +  +  +  +  :         56 :         while (desc->pos >= 0 || desc->filepos >= 0 || desc->snamepos >= 0) {
                   +  - ]
     159                 :            : 
     160         [ +  + ]:         56 :                 if (desc->pos >= 0) {
     161                 :         44 :                         descoption = &desc->options[0];
     162                 :         44 :                         desclen = &desc->len;
     163                 :         44 :                         descpos = &desc->pos;
     164         [ +  + ]:         12 :                 } else if (desc->filepos >= 0) {
     165                 :          8 :                         descoption = &desc->file[0];
     166                 :          8 :                         desclen = &desc->filelen;
     167                 :          8 :                         descpos = &desc->filepos;
     168         [ +  - ]:          4 :                 } else if (desc->snamepos >= 0) {
     169                 :          4 :                         descoption = &desc->sname[0];
     170                 :          4 :                         desclen = &desc->snamelen;
     171                 :          4 :                         descpos = &desc->snamepos;
     172                 :            :                 }
     173                 :            : 
     174   [ +  -  -  +  :         56 :                 assert_se(descoption && desclen && descpos);
             +  -  -  + ]
     175                 :            : 
     176         [ +  - ]:         56 :                 if (*desclen)
     177                 :         56 :                         test_ignore_opts(descoption, descpos, desclen);
     178                 :            : 
     179         [ +  + ]:         56 :                 if (*descpos < *desclen)
     180                 :         48 :                         break;
     181                 :            : 
     182         [ +  - ]:          8 :                 if (*descpos == *desclen)
     183                 :          8 :                         *descpos = -1;
     184                 :            :         }
     185                 :            : 
     186         [ -  + ]:         48 :         assert_se(descpos);
     187         [ -  + ]:         48 :         assert_se(*descpos != -1);
     188                 :            : 
     189                 :         48 :         optcode = descoption[*descpos];
     190                 :         48 :         optlen = descoption[*descpos + 1];
     191                 :            : 
     192         [ -  + ]:         48 :         if (verbose)
     193                 :          0 :                 printf("DHCP code %2d(%2d) len %2d(%2d) ", code, optcode,
     194                 :            :                                 len, optlen);
     195                 :            : 
     196         [ -  + ]:         48 :         assert_se(code == optcode);
     197         [ -  + ]:         48 :         assert_se(len == optlen);
     198                 :            : 
     199         [ +  + ]:        228 :         for (i = 0; i < len; i++) {
     200                 :            : 
     201         [ -  + ]:        180 :                 if (verbose)
     202                 :          0 :                         printf("0x%02x(0x%02x) ", ((uint8_t*) option)[i],
     203                 :          0 :                                         descoption[*descpos + 2 + i]);
     204                 :            : 
     205         [ -  + ]:        180 :                 assert_se(((uint8_t*) option)[i] == descoption[*descpos + 2 + i]);
     206                 :            :         }
     207                 :            : 
     208         [ -  + ]:         48 :         if (verbose)
     209                 :          0 :                 printf("\n");
     210                 :            : 
     211                 :         48 :         *descpos += optlen + 2;
     212                 :            : 
     213                 :         48 :         test_ignore_opts(descoption, descpos, desclen);
     214                 :            : 
     215   [ +  +  +  + ]:         48 :         if (desc->pos != -1 && desc->pos == desc->len)
     216                 :         16 :                 desc->pos = -1;
     217                 :            : 
     218   [ +  +  +  - ]:         48 :         if (desc->filepos != -1 && desc->filepos == desc->filelen)
     219                 :          8 :                 desc->filepos = -1;
     220                 :            : 
     221   [ +  +  +  + ]:         48 :         if (desc->snamepos != -1 && desc->snamepos == desc->snamelen)
     222                 :          4 :                 desc->snamepos = -1;
     223                 :            : 
     224                 :         48 :         return 0;
     225                 :            : }
     226                 :            : 
     227                 :         36 : static void test_options(struct option_desc *desc) {
     228                 :         36 :         uint8_t *options = NULL;
     229                 :         36 :         uint8_t *file = NULL;
     230                 :         36 :         uint8_t *sname = NULL;
     231                 :         36 :         int optlen = 0;
     232                 :         36 :         int filelen = 0;
     233                 :         36 :         int snamelen = 0;
     234                 :         36 :         int buflen = 0;
     235                 :         36 :         _cleanup_free_ DHCPMessage *message = NULL;
     236                 :            :         int res;
     237                 :            : 
     238         [ +  + ]:         36 :         if (desc) {
     239                 :         32 :                 file = &desc->file[0];
     240                 :         32 :                 filelen = desc->filelen;
     241         [ +  + ]:         32 :                 if (!filelen)
     242                 :         24 :                         desc->filepos = -1;
     243                 :            : 
     244                 :         32 :                 sname = &desc->sname[0];
     245                 :         32 :                 snamelen = desc->snamelen;
     246         [ +  + ]:         32 :                 if (!snamelen)
     247                 :         28 :                         desc->snamepos = -1;
     248                 :            : 
     249                 :         32 :                 options = &desc->options[0];
     250                 :         32 :                 optlen = desc->len;
     251                 :         32 :                 desc->pos = 0;
     252                 :            :         }
     253                 :         36 :         message = create_message(options, optlen, file, filelen,
     254                 :            :                                  sname, snamelen);
     255                 :            : 
     256                 :         36 :         buflen = sizeof(DHCPMessage) + optlen;
     257                 :            : 
     258         [ +  + ]:         36 :         if (!desc) {
     259         [ -  + ]:          4 :                 assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, NULL, NULL)) == -ENOMSG);
     260         [ +  + ]:         32 :         } else if (desc->success) {
     261         [ -  + ]:         20 :                 assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) >= 0);
     262   [ +  -  -  +  :         20 :                 assert_se(desc->pos == -1 && desc->filepos == -1 && desc->snamepos == -1);
             +  -  -  + ]
     263                 :            :         } else
     264         [ -  + ]:         12 :                 assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) < 0);
     265                 :            : 
     266         [ -  + ]:         36 :         if (verbose)
     267                 :          0 :                 printf("DHCP type %s\n", dhcp_type(res));
     268                 :         36 : }
     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                 :          4 : static void test_option_set(void) {
     282                 :          4 :         _cleanup_free_ DHCPMessage *result = NULL;
     283                 :          4 :         size_t offset = 0, len, pos;
     284                 :            :         unsigned i;
     285                 :            : 
     286                 :          4 :         result = malloc0(sizeof(DHCPMessage) + 11);
     287         [ -  + ]:          4 :         assert_se(result);
     288                 :            : 
     289                 :          4 :         result->options[0] = 'A';
     290                 :          4 :         result->options[1] = 'B';
     291                 :          4 :         result->options[2] = 'C';
     292                 :          4 :         result->options[3] = 'D';
     293                 :            : 
     294         [ -  + ]:          4 :         assert_se(dhcp_option_append(result, 0, &offset, 0, SD_DHCP_OPTION_PAD,
     295                 :            :                                      0, NULL) == -ENOBUFS);
     296         [ -  + ]:          4 :         assert_se(offset == 0);
     297                 :            : 
     298                 :          4 :         offset = 4;
     299         [ -  + ]:          4 :         assert_se(dhcp_option_append(result, 5, &offset, 0, SD_DHCP_OPTION_PAD,
     300                 :            :                                      0, NULL) == -ENOBUFS);
     301         [ -  + ]:          4 :         assert_se(offset == 4);
     302         [ -  + ]:          4 :         assert_se(dhcp_option_append(result, 6, &offset, 0, SD_DHCP_OPTION_PAD,
     303                 :            :                                      0, NULL) >= 0);
     304         [ -  + ]:          4 :         assert_se(offset == 5);
     305                 :            : 
     306                 :          4 :         offset = pos = 4;
     307                 :          4 :         len = 11;
     308   [ +  +  +  - ]:         16 :         while (pos < len && options[pos] != SD_DHCP_OPTION_END) {
     309         [ -  + ]:         12 :                 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         [ +  + ]:         12 :                 if (options[pos] == SD_DHCP_OPTION_PAD)
     315                 :          4 :                         pos++;
     316                 :            :                 else
     317                 :          8 :                         pos += 2 + options[pos + 1];
     318                 :            : 
     319         [ +  + ]:         12 :                 if (pos < len)
     320         [ -  + ]:          8 :                         assert_se(offset == pos);
     321                 :            :         }
     322                 :            : 
     323         [ +  + ]:         40 :         for (i = 0; i < 9; i++) {
     324         [ -  + ]:         36 :                 if (verbose)
     325                 :          0 :                         printf("%2u: 0x%02x(0x%02x) (options)\n", i, result->options[i],
     326                 :          0 :                                options[i]);
     327         [ -  + ]:         36 :                 assert_se(result->options[i] == options[i]);
     328                 :            :         }
     329                 :            : 
     330         [ -  + ]:          4 :         if (verbose)
     331                 :          0 :                 printf("%2d: 0x%02x(0x%02x) (options)\n", 9, result->options[9],
     332                 :            :                        SD_DHCP_OPTION_END);
     333                 :            : 
     334         [ -  + ]:          4 :         assert_se(result->options[9] == SD_DHCP_OPTION_END);
     335                 :            : 
     336         [ -  + ]:          4 :         if (verbose)
     337                 :          0 :                 printf("%2d: 0x%02x(0x%02x) (options)\n", 10, result->options[10],
     338                 :            :                        SD_DHCP_OPTION_PAD);
     339                 :            : 
     340         [ -  + ]:          4 :         assert_se(result->options[10] == SD_DHCP_OPTION_PAD);
     341                 :            : 
     342         [ +  + ]:         48 :         for (i = 0; i < pos - 8; i++) {
     343         [ -  + ]:         44 :                 if (verbose)
     344                 :          0 :                         printf("%2u: 0x%02x(0x%02x) (sname)\n", i, result->sname[i],
     345                 :          0 :                                options[i + 9]);
     346         [ -  + ]:         44 :                 assert_se(result->sname[i] == options[i + 9]);
     347                 :            :         }
     348                 :            : 
     349         [ -  + ]:          4 :         if (verbose)
     350                 :          0 :                 printf ("\n");
     351                 :          4 : }
     352                 :            : 
     353                 :          4 : int main(int argc, char *argv[]) {
     354                 :            :         unsigned i;
     355                 :            : 
     356                 :          4 :         test_invalid_buffer_length();
     357                 :          4 :         test_message_init();
     358                 :            : 
     359                 :          4 :         test_options(NULL);
     360                 :            : 
     361         [ +  + ]:         36 :         for (i = 0; i < ELEMENTSOF(option_tests); i++)
     362                 :         32 :                 test_options(&option_tests[i]);
     363                 :            : 
     364                 :          4 :         test_option_set();
     365                 :            : 
     366                 :          4 :         return 0;
     367                 :            : }

Generated by: LCOV version 1.14