Line 0
Link Here
|
0 |
- |
1 |
From 4021058d729fd618e5770300664ecfcc6fd29d5d Mon Sep 17 00:00:00 2001 |
|
|
2 |
From: Chris Rorvick <chris@rorvick.com> |
3 |
Date: Tue, 28 May 2019 00:44:52 -0500 |
4 |
Subject: [PATCH] prefer routable IPv6 addresses over link-local |
5 |
|
6 |
Currently the IPv6 address provided for an interface in the $(sys.inet6) |
7 |
data is arbitrary if more than one address is bound to that interface. |
8 |
Given that IPv6 requires all interfaces have a link-local address, this |
9 |
is a common scenario. Add a mechanism to GetProcFileInfo() to choose |
10 |
between the previous and new entries if more than one is found for an |
11 |
extracted key, and use this mechanism to rank link-local addresses below |
12 |
others. |
13 |
|
14 |
Also, the post-processing functions passed to GetProcFileInfo() have a |
15 |
strange return value. This is seemingly due to a misunderstanding with |
16 |
how function pointer types relate to function definitions. Clean this |
17 |
up. |
18 |
--- |
19 |
libenv/unix_iface.c | 106 +++++++++++++++++++++++++++++++++++--------- |
20 |
1 file changed, 86 insertions(+), 20 deletions(-) |
21 |
|
22 |
diff --git a/libenv/unix_iface.c b/libenv/unix_iface.c |
23 |
index c62e1cb73..0adbb0a7b 100644 |
24 |
--- a/libenv/unix_iface.c |
25 |
+++ b/libenv/unix_iface.c |
26 |
@@ -88,6 +88,7 @@ static void InitIgnoreInterfaces(void); |
27 |
static Rlist *IGNORE_INTERFACES = NULL; /* GLOBAL_E */ |
28 |
|
29 |
typedef void (*ProcPostProcessFn)(void *ctx, void *json); |
30 |
+typedef JsonElement * (*ProcTiebreakerFn)(JsonElement *prev_item, JsonElement *this_item); |
31 |
|
32 |
|
33 |
/*********************************************************************/ |
34 |
@@ -1021,7 +1022,7 @@ static void NetworkingRoutesPostProcessInfo( |
35 |
# endif |
36 |
} |
37 |
|
38 |
-static ProcPostProcessFn NetworkingIPv6RoutesPostProcessInfo( |
39 |
+static void NetworkingIPv6RoutesPostProcessInfo( |
40 |
ARG_UNUSED void *passed_ctx, ARG_LINUX_ONLY void *json) |
41 |
{ |
42 |
# if defined (__linux__) |
43 |
@@ -1054,10 +1055,9 @@ static ProcPostProcessFn NetworkingIPv6RoutesPostProcessInfo( |
44 |
// like we do with IPv4 routes |
45 |
|
46 |
# endif |
47 |
- return NULL; |
48 |
} |
49 |
|
50 |
-static ProcPostProcessFn NetworkingIPv6AddressesPostProcessInfo(ARG_UNUSED void *passed_ctx, void *json) |
51 |
+static void NetworkingIPv6AddressesPostProcessInfo(ARG_UNUSED void *passed_ctx, void *json) |
52 |
{ |
53 |
JsonElement *entry = json; |
54 |
|
55 |
@@ -1066,7 +1066,50 @@ static ProcPostProcessFn NetworkingIPv6AddressesPostProcessInfo(ARG_UNUSED void |
56 |
JsonExtractParsedNumber(entry, "raw_device_number", "device_number", true, false); |
57 |
JsonExtractParsedNumber(entry, "raw_prefix_length", "prefix_length", true, false); |
58 |
JsonExtractParsedNumber(entry, "raw_scope", "scope", true, false); |
59 |
- return NULL; |
60 |
+} |
61 |
+ |
62 |
+static unsigned RankIPv6Address(const char *address) |
63 |
+{ |
64 |
+ unsigned long first_word = 0; |
65 |
+ char *end; |
66 |
+ |
67 |
+ if (address == NULL) |
68 |
+ { |
69 |
+ return 0; |
70 |
+ } |
71 |
+ |
72 |
+ first_word = strtoul(address, &end, 16); |
73 |
+ |
74 |
+ if (*end != ':') |
75 |
+ { |
76 |
+ return 0; // invalid IPv6 address? |
77 |
+ } |
78 |
+ |
79 |
+ if ((first_word & 0xffc0) == 0xfe80) |
80 |
+ { |
81 |
+ // link-local (fe80:://10) |
82 |
+ |
83 |
+ return 1; |
84 |
+ } |
85 |
+ else |
86 |
+ { |
87 |
+ return 2; |
88 |
+ } |
89 |
+} |
90 |
+ |
91 |
+static JsonElement *NetworkingIPv6AddressesTiebreaker(JsonElement *prev_item, JsonElement *this_item) |
92 |
+{ |
93 |
+ const char *prev_addr = JsonObjectGetAsString(prev_item, "address"); |
94 |
+ const char *this_addr = JsonObjectGetAsString(this_item, "address"); |
95 |
+ |
96 |
+ if (RankIPv6Address(this_addr) >= RankIPv6Address(prev_addr)) |
97 |
+ { |
98 |
+ return this_item; |
99 |
+ } |
100 |
+ else |
101 |
+ { |
102 |
+ return prev_item; |
103 |
+ } |
104 |
} |
105 |
|
106 |
/*******************************************************************/ |
107 |
@@ -1095,7 +1138,7 @@ static const char* GetPortStateString(ARG_LINUX_ONLY int state) |
108 |
|
109 |
// used in evalfunction.c but defined here so |
110 |
// JsonRewriteParsedIPAddress() etc. can stay local |
111 |
-ProcPostProcessFn NetworkingPortsPostProcessInfo(ARG_UNUSED void *passed_ctx, void *json) |
112 |
+void NetworkingPortsPostProcessInfo(ARG_UNUSED void *passed_ctx, void *json) |
113 |
{ |
114 |
JsonElement *conn = json; |
115 |
|
116 |
@@ -1112,8 +1155,6 @@ ProcPostProcessFn NetworkingPortsPostProcessInfo(ARG_UNUSED void *passed_ctx, vo |
117 |
JsonObjectAppendString(conn, "state", GetPortStateString(num_state)); |
118 |
} |
119 |
} |
120 |
- |
121 |
- return NULL; |
122 |
} |
123 |
|
124 |
/*******************************************************************/ |
125 |
@@ -1180,7 +1221,7 @@ static JsonElement* GetNetworkingStatsInfo(const char *filename) |
126 |
// always returns the parsed data. If the key is not NULL, also |
127 |
// creates a sys.KEY variable. |
128 |
|
129 |
-JsonElement* GetProcFileInfo(EvalContext *ctx, const char* filename, const char* key, const char* extracted_key, ProcPostProcessFn post, const char* regex) |
130 |
+JsonElement* GetProcFileInfo(EvalContext *ctx, const char* filename, const char* key, const char* extracted_key, ProcPostProcessFn post, ProcTiebreakerFn tiebreak, const char* regex) |
131 |
{ |
132 |
JsonElement *info = NULL; |
133 |
bool extract_key_mode = (extracted_key != NULL); |
134 |
@@ -1218,14 +1259,39 @@ JsonElement* GetProcFileInfo(EvalContext *ctx, const char* filename, const char* |
135 |
|
136 |
if (extract_key_mode) |
137 |
{ |
138 |
- if (JsonObjectGetAsString(item, extracted_key) == NULL) |
139 |
+ const char *extracted_key_value = JsonObjectGetAsString(item, extracted_key); |
140 |
+ |
141 |
+ if (extracted_key_value == NULL) |
142 |
{ |
143 |
Log(LOG_LEVEL_ERR, "While parsing %s, looked to extract key %s but couldn't find it in line %s", filename, extracted_key, line); |
144 |
} |
145 |
else |
146 |
{ |
147 |
- Log(LOG_LEVEL_DEBUG, "While parsing %s, got key %s from line %s", filename, JsonObjectGetAsString(item, extracted_key), line); |
148 |
- JsonObjectAppendElement(info, JsonObjectGetAsString(item, extracted_key), item); |
149 |
+ JsonElement *prev_item = JsonObjectGet(info, extracted_key_value); |
150 |
+ |
151 |
+ Log(LOG_LEVEL_DEBUG, "While parsing %s, got key %s from line %s", filename, extracted_key_value, line); |
152 |
+ |
153 |
+ if (prev_item != NULL && tiebreak != NULL) |
154 |
+ { |
155 |
+ JsonElement *winner = (*tiebreak)(prev_item, item); |
156 |
+ |
157 |
+ if (winner == prev_item) |
158 |
+ { |
159 |
+ Log(LOG_LEVEL_DEBUG, "Multiple entries for key %s, preferring previous value", extracted_key_value); |
160 |
+ |
161 |
+ JsonDestroy(item); |
162 |
+ item = NULL; |
163 |
+ } |
164 |
+ else |
165 |
+ { |
166 |
+ Log(LOG_LEVEL_DEBUG, "Multiple entries for key %s, preferring new value", extracted_key_value); |
167 |
+ } |
168 |
+ } |
169 |
+ |
170 |
+ if (item != NULL) |
171 |
+ { |
172 |
+ JsonObjectAppendElement(info, extracted_key_value, item); |
173 |
+ } |
174 |
} |
175 |
} |
176 |
else |
177 |
@@ -1274,7 +1340,7 @@ void GetNetworkingInfo(EvalContext *ctx) |
178 |
} |
179 |
|
180 |
BufferPrintf(pbuf, "%s/proc/net/route", procdir_root); |
181 |
- JsonElement *routes = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, (ProcPostProcessFn) &NetworkingRoutesPostProcessInfo, |
182 |
+ JsonElement *routes = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, &NetworkingRoutesPostProcessInfo, NULL, |
183 |
// format: Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT |
184 |
// eth0 00000000 0102A8C0 0003 0 0 1024 00000000 0 0 0 |
185 |
"^(?<interface>\\S+)\\t(?<raw_dest>[[:xdigit:]]+)\\t(?<raw_gw>[[:xdigit:]]+)\\t(?<raw_flags>[[:xdigit:]]+)\\t(?<refcnt>\\d+)\\t(?<use>\\d+)\\t(?<metric>[[:xdigit:]]+)\\t(?<raw_mask>[[:xdigit:]]+)\\t(?<mtu>\\d+)\\t(?<window>\\d+)\\t(?<irtt>[[:xdigit:]]+)"); |
186 |
@@ -1322,7 +1388,7 @@ void GetNetworkingInfo(EvalContext *ctx) |
187 |
JsonElement *inet6 = JsonObjectCreate(3); |
188 |
|
189 |
BufferPrintf(pbuf, "%s/proc/net/snmp6", procdir_root); |
190 |
- JsonElement *inet6_stats = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, NULL, |
191 |
+ JsonElement *inet6_stats = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, NULL, NULL, |
192 |
"^\\s*(?<key>\\S+)\\s+(?<value>\\d+)"); |
193 |
|
194 |
if (inet6_stats != NULL) |
195 |
@@ -1348,7 +1414,7 @@ void GetNetworkingInfo(EvalContext *ctx) |
196 |
} |
197 |
|
198 |
BufferPrintf(pbuf, "%s/proc/net/ipv6_route", procdir_root); |
199 |
- JsonElement *inet6_routes = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, (ProcPostProcessFn) &NetworkingIPv6RoutesPostProcessInfo, |
200 |
+ JsonElement *inet6_routes = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, &NetworkingIPv6RoutesPostProcessInfo, NULL, |
201 |
// format: dest dest_prefix source source_prefix next_hop metric refcnt use flags interface |
202 |
// fe800000000000000000000000000000 40 00000000000000000000000000000000 00 00000000000000000000000000000000 00000100 00000000 00000000 00000001 eth0 |
203 |
"^(?<raw_dest>[[:xdigit:]]+)\\s+(?<dest_prefix>[[:xdigit:]]+)\\s+" |
204 |
@@ -1363,7 +1429,7 @@ void GetNetworkingInfo(EvalContext *ctx) |
205 |
} |
206 |
|
207 |
BufferPrintf(pbuf, "%s/proc/net/if_inet6", procdir_root); |
208 |
- JsonElement *inet6_addresses = GetProcFileInfo(ctx, BufferData(pbuf), NULL, "interface", (ProcPostProcessFn) &NetworkingIPv6AddressesPostProcessInfo, |
209 |
+ JsonElement *inet6_addresses = GetProcFileInfo(ctx, BufferData(pbuf), NULL, "interface", &NetworkingIPv6AddressesPostProcessInfo, &NetworkingIPv6AddressesTiebreaker, |
210 |
// format: address device_number prefix_length scope flags interface_name |
211 |
// 00000000000000000000000000000001 01 80 10 80 lo |
212 |
// fe80000000000000004249fffebdd7b4 04 40 20 80 docker0 |
213 |
@@ -1387,7 +1453,7 @@ void GetNetworkingInfo(EvalContext *ctx) |
214 |
|
215 |
BufferPrintf(pbuf, "%s/proc/net/dev", procdir_root); |
216 |
JsonElement *interfaces_data = |
217 |
- GetProcFileInfo(ctx, BufferData(pbuf), "interfaces_data", "device", NULL, |
218 |
+ GetProcFileInfo(ctx, BufferData(pbuf), "interfaces_data", "device", NULL, NULL, |
219 |
"^\\s*(?<device>[^:]+)\\s*:\\s*" |
220 |
// All of the below are just decimal digits separated by spaces |
221 |
"(?<receive_bytes>\\d+)\\s+" |
222 |
@@ -1420,28 +1486,28 @@ JsonElement* GetNetworkingConnections(EvalContext *ctx) |
223 |
Buffer *pbuf = BufferNew(); |
224 |
|
225 |
BufferPrintf(pbuf, "%s/proc/net/tcp", procdir_root); |
226 |
- data = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, (ProcPostProcessFn) &NetworkingPortsPostProcessInfo, ports_regex); |
227 |
+ data = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, &NetworkingPortsPostProcessInfo, NULL, ports_regex); |
228 |
if (data != NULL) |
229 |
{ |
230 |
JsonObjectAppendElement(json, "tcp", data); |
231 |
} |
232 |
|
233 |
BufferPrintf(pbuf, "%s/proc/net/tcp6", procdir_root); |
234 |
- data = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, (ProcPostProcessFn) &NetworkingPortsPostProcessInfo, ports_regex); |
235 |
+ data = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, &NetworkingPortsPostProcessInfo, NULL, ports_regex); |
236 |
if (data != NULL) |
237 |
{ |
238 |
JsonObjectAppendElement(json, "tcp6", data); |
239 |
} |
240 |
|
241 |
BufferPrintf(pbuf, "%s/proc/net/udp", procdir_root); |
242 |
- data = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, (ProcPostProcessFn) &NetworkingPortsPostProcessInfo, ports_regex); |
243 |
+ data = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, &NetworkingPortsPostProcessInfo, NULL, ports_regex); |
244 |
if (data != NULL) |
245 |
{ |
246 |
JsonObjectAppendElement(json, "udp", data); |
247 |
} |
248 |
|
249 |
BufferPrintf(pbuf, "%s/proc/net/udp6", procdir_root); |
250 |
- data = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, (ProcPostProcessFn) &NetworkingPortsPostProcessInfo, ports_regex); |
251 |
+ data = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, &NetworkingPortsPostProcessInfo, NULL, ports_regex); |
252 |
if (data != NULL) |
253 |
{ |
254 |
JsonObjectAppendElement(json, "udp6", data); |
255 |
-- |
256 |
2.24.1 |
257 |
|