| #include <netinet/in.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdint.h> |
| |
| #define OPT_X 42 |
| #define OPT_Y 43 |
| #define OPT_Z 44 |
| |
| static void * |
| encode_inet6_opt (socklen_t *elp) |
| { |
| void *eb = NULL; |
| socklen_t el; |
| int cl; |
| void *db; |
| int offset; |
| uint8_t val1; |
| uint16_t val2; |
| uint32_t val4; |
| uint64_t val8; |
| |
| *elp = 0; |
| #define CHECK() \ |
| if (cl == -1) \ |
| { \ |
| printf ("cl == -1 on line %d\n", __LINE__); \ |
| free (eb); \ |
| return NULL; \ |
| } |
| |
| /* Estimate the length */ |
| cl = inet6_opt_init (NULL, 0); |
| CHECK (); |
| cl = inet6_opt_append (NULL, 0, cl, OPT_X, 12, 8, NULL); |
| CHECK (); |
| cl = inet6_opt_append (NULL, 0, cl, OPT_Y, 7, 4, NULL); |
| CHECK (); |
| cl = inet6_opt_append (NULL, 0, cl, OPT_Z, 7, 1, NULL); |
| CHECK (); |
| cl = inet6_opt_finish (NULL, 0, cl); |
| CHECK (); |
| el = cl; |
| |
| eb = malloc (el + 8); |
| if (eb == NULL) |
| { |
| puts ("malloc failed"); |
| return NULL; |
| } |
| /* Canary. */ |
| memcpy (eb + el, "deadbeef", 8); |
| |
| cl = inet6_opt_init (eb, el); |
| CHECK (); |
| |
| cl = inet6_opt_append (eb, el, cl, OPT_X, 12, 8, &db); |
| CHECK (); |
| val4 = 0x12345678; |
| offset = inet6_opt_set_val (db, 0, &val4, sizeof (val4)); |
| val8 = 0x0102030405060708LL; |
| inet6_opt_set_val (db, offset, &val8, sizeof (val8)); |
| |
| cl = inet6_opt_append (eb, el, cl, OPT_Y, 7, 4, &db); |
| CHECK (); |
| val1 = 0x01; |
| offset = inet6_opt_set_val (db, 0, &val1, sizeof (val1)); |
| val2 = 0x1331; |
| offset = inet6_opt_set_val (db, offset, &val2, sizeof (val2)); |
| val4 = 0x01020304; |
| inet6_opt_set_val (db, offset, &val4, sizeof (val4)); |
| |
| cl = inet6_opt_append (eb, el, cl, OPT_Z, 7, 1, &db); |
| CHECK (); |
| inet6_opt_set_val (db, 0, (void *) "abcdefg", 7); |
| |
| cl = inet6_opt_finish (eb, el, cl); |
| CHECK (); |
| |
| if (memcmp (eb + el, "deadbeef", 8) != 0) |
| { |
| puts ("Canary corrupted"); |
| free (eb); |
| return NULL; |
| } |
| *elp = el; |
| return eb; |
| } |
| |
| int |
| decode_inet6_opt (void *eb, socklen_t el) |
| { |
| int ret = 0; |
| int seq = 0; |
| int cl = 0; |
| int offset; |
| uint8_t type; |
| socklen_t len; |
| uint8_t val1; |
| uint16_t val2; |
| uint32_t val4; |
| uint64_t val8; |
| void *db; |
| char buf[8]; |
| |
| while ((cl = inet6_opt_next (eb, el, cl, &type, &len, &db)) != -1) |
| switch (type) |
| { |
| case OPT_X: |
| if (seq++ != 0) |
| { |
| puts ("OPT_X is not first"); |
| ret = 1; |
| } |
| if (len != 12) |
| { |
| printf ("OPT_X's length %d != 12\n", len); |
| ret = 1; |
| } |
| offset = inet6_opt_get_val (db, 0, &val4, sizeof (val4)); |
| if (val4 != 0x12345678) |
| { |
| printf ("OPT_X's val4 %x != 0x12345678\n", val4); |
| ret = 1; |
| } |
| offset = inet6_opt_get_val (db, offset, &val8, sizeof (val8)); |
| if (offset != len || val8 != 0x0102030405060708LL) |
| { |
| printf ("OPT_X's val8 %llx != 0x0102030405060708\n", |
| (long long) val8); |
| ret = 1; |
| } |
| break; |
| case OPT_Y: |
| if (seq++ != 1) |
| { |
| puts ("OPT_Y is not second"); |
| ret = 1; |
| } |
| if (len != 7) |
| { |
| printf ("OPT_Y's length %d != 7\n", len); |
| ret = 1; |
| } |
| offset = inet6_opt_get_val (db, 0, &val1, sizeof (val1)); |
| if (val1 != 0x01) |
| { |
| printf ("OPT_Y's val1 %x != 0x01\n", val1); |
| ret = 1; |
| } |
| offset = inet6_opt_get_val (db, offset, &val2, sizeof (val2)); |
| if (val2 != 0x1331) |
| { |
| printf ("OPT_Y's val2 %x != 0x1331\n", val2); |
| ret = 1; |
| } |
| offset = inet6_opt_get_val (db, offset, &val4, sizeof (val4)); |
| if (offset != len || val4 != 0x01020304) |
| { |
| printf ("OPT_Y's val4 %x != 0x01020304\n", val4); |
| ret = 1; |
| } |
| break; |
| case OPT_Z: |
| if (seq++ != 2) |
| { |
| puts ("OPT_Z is not third"); |
| ret = 1; |
| } |
| if (len != 7) |
| { |
| printf ("OPT_Z's length %d != 7\n", len); |
| ret = 1; |
| } |
| offset = inet6_opt_get_val (db, 0, buf, 7); |
| if (offset != len || memcmp (buf, "abcdefg", 7) != 0) |
| { |
| buf[7] = '\0'; |
| printf ("OPT_Z's buf \"%s\" != \"abcdefg\"\n", buf); |
| ret = 1; |
| } |
| break; |
| default: |
| printf ("Unknown option %d\n", type); |
| ret = 1; |
| break; |
| } |
| if (seq != 3) |
| { |
| puts ("Didn't see all of OPT_X, OPT_Y and OPT_Z"); |
| ret = 1; |
| } |
| return ret; |
| } |
| |
| int |
| main (void) |
| { |
| void *eb; |
| socklen_t el; |
| eb = encode_inet6_opt (&el); |
| if (eb == NULL) |
| return 1; |
| if (decode_inet6_opt (eb, el)) |
| return 1; |
| return 0; |
| } |