Branch data Line data Source code
1 : : /*
2 : : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License").
5 : : * You may not use this file except in compliance with the License.
6 : : * A copy of the License is located at
7 : : *
8 : : * http://aws.amazon.com/apache2.0
9 : : *
10 : : * or in the "license" file accompanying this file. This file is distributed
11 : : * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 : : * express or implied. See the License for the specific language governing
13 : : * permissions and limitations under the License.
14 : : */
15 : :
16 : : #include "utils/s2n_rfc5952.h"
17 : :
18 : : #include <stdio.h>
19 : : /* <winsock2.h> internally includes core elements from <windows.h>. For historical
20 : : * reasons, <windows.h> defaults to including <winsock.h> (Winsock 1.1), whose
21 : : * declarations conflict with <winsock2.h> (Winsock 2). Defining WIN32_LEAN_AND_MEAN
22 : : * before including <winsock2.h> prevents this transitive <winsock.h> inclusion.
23 : : * https://learn.microsoft.com/en-us/windows/win32/winsock/include-files-2
24 : : */
25 : : #ifdef _WIN32
26 : : #define WIN32_LEAN_AND_MEAN
27 : : #include <winsock2.h>
28 : : #else
29 : : #include <sys/socket.h>
30 : : #endif
31 : : #include <sys/types.h>
32 : :
33 : : #include "error/s2n_errno.h"
34 : : #include "utils/s2n_safety.h"
35 : :
36 : : static uint8_t dec[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
37 : : static uint8_t hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
38 : :
39 : : S2N_RESULT s2n_inet_ntop(int af, const void *addr, struct s2n_blob *dst)
40 : 12 : {
41 : 12 : const uint8_t *bytes = addr;
42 : 12 : uint8_t *cursor = dst->data;
43 : :
44 [ + + ]: 12 : if (af == AF_INET) {
45 [ # # ][ - + ]: 4 : RESULT_ENSURE(dst->size >= sizeof("111.222.333.444"), S2N_ERR_SIZE_MISMATCH);
46 : :
47 [ + + ]: 20 : for (int i = 0; i < 4; i++) {
48 [ + + ]: 16 : if (bytes[i] / 100) {
49 : 11 : *cursor++ = dec[bytes[i] / 100];
50 : 11 : }
51 [ + + ]: 16 : if (bytes[i] >= 10) {
52 : 11 : *cursor++ = dec[(bytes[i] % 100) / 10];
53 : 11 : }
54 : 16 : *cursor++ = dec[(bytes[i] % 10)];
55 : 16 : *cursor++ = '.';
56 : 16 : }
57 : :
58 : 4 : *--cursor = '\0';
59 : :
60 : 4 : return S2N_RESULT_OK;
61 : 4 : }
62 : :
63 [ + + ]: 8 : if (af == AF_INET6) {
64 [ # # ][ - + ]: 7 : RESULT_ENSURE(dst->size >= sizeof("1111:2222:3333:4444:5555:6666:7777:8888"), S2N_ERR_SIZE_MISMATCH);
65 : :
66 : : /* See Section 4 of RFC5952 for the rules we are going to follow here
67 : : *
68 : : * Here's the general algorithm:
69 : : *
70 : : * 1/ Treat the bytes as 8 16-bit fields
71 : : * 2/ Find the longest run of 16-bit fields.
72 : : * 3/ or if there are two or more equal length longest runs, go with the left-most run
73 : : * 4/ Make that run ::
74 : : * 5/ Print the remaining 16-bit fields in lowercase hex, no leading zeroes
75 : : */
76 : :
77 : 7 : uint16_t octets[8] = { 0 };
78 : :
79 : 7 : int longest_run_start = 0;
80 : 7 : int longest_run_length = 0;
81 : 7 : int current_run_length = 0;
82 : :
83 : : /* 2001:db8::1:0:0:1 */
84 : :
85 : : /* Find the longest run of zeroes */
86 [ + + ]: 63 : for (int i = 0; i < 8; i++) {
87 : 56 : octets[i] = (bytes[i * 2] << 8) + bytes[(i * 2) + 1];
88 : :
89 [ + + ]: 56 : if (octets[i]) {
90 : 20 : current_run_length = 0;
91 : 36 : } else {
92 : 36 : current_run_length++;
93 : 36 : }
94 : :
95 [ + + ]: 56 : if (current_run_length > longest_run_length) {
96 : 34 : longest_run_length = current_run_length;
97 : 34 : longest_run_start = (i - current_run_length) + 1;
98 : 34 : }
99 : 56 : }
100 : :
101 [ + + ]: 36 : for (int i = 0; i < 8; i++) {
102 [ + + ][ + + ]: 29 : if (i == longest_run_start && longest_run_length > 1) {
103 [ + + ]: 6 : if (i == 0) {
104 : 3 : *cursor++ = ':';
105 : 3 : }
106 : :
107 [ + + ]: 6 : if (longest_run_length == 8) {
108 : 1 : *cursor++ = ':';
109 : 1 : }
110 : :
111 : 6 : i += longest_run_length - 1;
112 : :
113 : 23 : } else {
114 : 23 : uint8_t nibbles[4] = { (octets[i] & 0xF000) >> 12,
115 : 23 : (octets[i] & 0x0F00) >> 8,
116 : 23 : (octets[i] & 0x00F0) >> 4,
117 : 23 : (octets[i] & 0x000F) };
118 : :
119 : : /* Skip up to three leading zeroes */
120 : 23 : int j = 0;
121 [ + + ]: 72 : for (j = 0; j < 3; j++) {
122 [ + + ]: 57 : if (nibbles[j]) {
123 : 8 : break;
124 : 8 : }
125 : 57 : }
126 : :
127 [ + + ]: 66 : for (; j < 4; j++) {
128 : 43 : *cursor++ = hex[nibbles[j]];
129 : 43 : }
130 : 23 : }
131 : :
132 : 29 : *cursor++ = ':';
133 : 29 : }
134 : :
135 : 7 : *--cursor = '\0';
136 : :
137 : 7 : return S2N_RESULT_OK;
138 : 7 : }
139 : :
140 [ + - ]: 1 : RESULT_BAIL(S2N_ERR_INVALID_ARGUMENT);
141 : 1 : }
|