@@ -14,67 +14,214 @@ namespace {
14
14
using TUnboxedValue = NKikimr::NUdf::TUnboxedValue;
15
15
using TUnboxedValuePod = NKikimr::NUdf::TUnboxedValuePod;
16
16
17
+ ui8 GetAddressRangePrefix (const TIpAddressRange& range) {
18
+ if (range.Contains (TIpv6Address (ui128 (0 ), TIpv6Address::Ipv6)) && range.Contains (TIpv6Address (ui128 (-1 ), TIpv6Address::Ipv6))) {
19
+ return 0 ;
20
+ }
21
+ if (range.Size () == 0 ) {
22
+ return range.Type () == TIpv6Address::Ipv4 ? 32 : 128 ;
23
+ }
24
+ ui128 size = range.Size ();
25
+ size_t sizeLog = MostSignificantBit (size);
26
+ return ui8 ((range.Type () == TIpv6Address::Ipv4 ? 32 : 128 ) - sizeLog);
27
+ }
28
+
17
29
struct TRawIp4 {
18
30
ui8 a, b, c, d;
31
+
32
+ static TRawIp4 FromIpAddress (const TIpv6Address& addr) {
33
+ ui128 x = addr;
34
+ return {
35
+ ui8 (x >> 24 & 0xff ),
36
+ ui8 (x >> 16 & 0xff ),
37
+ ui8 (x >> 8 & 0xff ),
38
+ ui8 (x & 0xff )
39
+ };
40
+ }
41
+
42
+ static TRawIp4 MaskFromPrefix (ui8 prefix) {
43
+ ui128 x = ui128 (-1 ) << int (32 - prefix);
44
+ x &= ui128 (ui32 (-1 ));
45
+ return FromIpAddress ({x, TIpv6Address::Ipv4});
46
+ }
47
+
48
+ TIpv6Address ToIpAddress () const {
49
+ return {a, b, c, d};
50
+ }
51
+
52
+ std::pair<TRawIp4, TRawIp4> ApplyMask (const TRawIp4& mask) const {
53
+ return {{
54
+ ui8 (a & mask.a ),
55
+ ui8 (b & mask.b ),
56
+ ui8 (c & mask.c ),
57
+ ui8 (d & mask.d )
58
+ },{
59
+ ui8 (a | ~mask.a ),
60
+ ui8 (b | ~mask.b ),
61
+ ui8 (c | ~mask.c ),
62
+ ui8 (d | ~mask.d )
63
+ }};
64
+ }
65
+ };
66
+
67
+ struct TRawIp4Subnet {
68
+ TRawIp4 base, mask;
69
+
70
+ static TRawIp4Subnet FromIpRange (const TIpAddressRange& range) {
71
+ return {TRawIp4::FromIpAddress (*range.Begin ()), TRawIp4::MaskFromPrefix (GetAddressRangePrefix (range))};
72
+ }
73
+
74
+ TIpAddressRange ToIpRange () const {
75
+ auto range = base.ApplyMask (mask);
76
+ return {range.first .ToIpAddress (), range.second .ToIpAddress ()};
77
+ }
19
78
};
20
79
21
80
struct TRawIp6 {
22
81
ui8 a1, a0, b1, b0, c1, c0, d1, d0, e1 , e0 , f1, f0, g1, g0, h1, h0;
82
+
83
+ static TRawIp6 FromIpAddress (const TIpv6Address& addr) {
84
+ ui128 x = addr;
85
+ return {
86
+ ui8 (x >> 120 & 0xff ), ui8 (x >> 112 & 0xff ),
87
+ ui8 (x >> 104 & 0xff ), ui8 (x >> 96 & 0xff ),
88
+ ui8 (x >> 88 & 0xff ), ui8 (x >> 80 & 0xff ),
89
+ ui8 (x >> 72 & 0xff ), ui8 (x >> 64 & 0xff ),
90
+ ui8 (x >> 56 & 0xff ), ui8 (x >> 48 & 0xff ),
91
+ ui8 (x >> 40 & 0xff ), ui8 (x >> 32 & 0xff ),
92
+ ui8 (x >> 24 & 0xff ), ui8 (x >> 16 & 0xff ),
93
+ ui8 (x >> 8 & 0xff ), ui8 (x & 0xff )
94
+ };
95
+ }
96
+
97
+ static TRawIp6 MaskFromPrefix (ui8 prefix) {
98
+ ui128 x = ui128 (-1 ) << int (128 - prefix);
99
+ if (prefix == 0 ) x = 0 ;
100
+ return FromIpAddress ({x, TIpv6Address::Ipv6});
101
+ }
102
+
103
+ TIpv6Address ToIpAddress () const {
104
+ return {ui16 (ui32 (a1) << ui32 (8 ) | ui32 (a0)),
105
+ ui16 (ui32 (b1) << ui32 (8 ) | ui32 (b0)),
106
+ ui16 (ui32 (c1) << ui32 (8 ) | ui32 (c0)),
107
+ ui16 (ui32 (d1) << ui32 (8 ) | ui32 (d0)),
108
+ ui16 (ui32 (e1 ) << ui32 (8 ) | ui32 (e0 )),
109
+ ui16 (ui32 (f1) << ui32 (8 ) | ui32 (f0)),
110
+ ui16 (ui32 (g1) << ui32 (8 ) | ui32 (g0)),
111
+ ui16 (ui32 (h1) << ui32 (8 ) | ui32 (h0)),
112
+ };
113
+ }
114
+
115
+ std::pair<TRawIp6, TRawIp6> ApplyMask (const TRawIp6& mask) const {
116
+ return { {
117
+ ui8 (a1 & mask.a1 ),
118
+ ui8 (a0 & mask.a0 ),
119
+ ui8 (b1 & mask.b1 ),
120
+ ui8 (b0 & mask.b0 ),
121
+ ui8 (c1 & mask.c1 ),
122
+ ui8 (c0 & mask.c0 ),
123
+ ui8 (d1 & mask.d1 ),
124
+ ui8 (d0 & mask.d0 ),
125
+ ui8 (e1 & mask.e1 ),
126
+ ui8 (e0 & mask.e0 ),
127
+ ui8 (f1 & mask.f1 ),
128
+ ui8 (f0 & mask.f0 ),
129
+ ui8 (g1 & mask.g1 ),
130
+ ui8 (g0 & mask.g0 ),
131
+ ui8 (h1 & mask.h1 ),
132
+ ui8 (h0 & mask.h0 )
133
+ }, {
134
+ ui8 (a1 | ~mask.a1 ),
135
+ ui8 (a0 | ~mask.a0 ),
136
+ ui8 (b1 | ~mask.b1 ),
137
+ ui8 (b0 | ~mask.b0 ),
138
+ ui8 (c1 | ~mask.c1 ),
139
+ ui8 (c0 | ~mask.c0 ),
140
+ ui8 (d1 | ~mask.d1 ),
141
+ ui8 (d0 | ~mask.d0 ),
142
+ ui8 (e1 | ~mask.e1 ),
143
+ ui8 (e0 | ~mask.e0 ),
144
+ ui8 (f1 | ~mask.f1 ),
145
+ ui8 (f0 | ~mask.f0 ),
146
+ ui8 (g1 | ~mask.g1 ),
147
+ ui8 (g0 | ~mask.g0 ),
148
+ ui8 (h1 | ~mask.h1 ),
149
+ ui8 (h0 | ~mask.h0 )
150
+ }};
151
+ }
152
+ };
153
+
154
+ struct TRawIp6Subnet {
155
+ TRawIp6 base, mask;
156
+
157
+ static TRawIp6Subnet FromIpRange (const TIpAddressRange& range) {
158
+ return {TRawIp6::FromIpAddress (*range.Begin ()), TRawIp6::MaskFromPrefix (GetAddressRangePrefix (range))};
159
+ }
160
+
161
+ TIpAddressRange ToIpRange () const {
162
+ auto range = base.ApplyMask (mask);
163
+ return {range.first .ToIpAddress (), range.second .ToIpAddress ()};
164
+ }
23
165
};
24
166
25
167
TIpv6Address DeserializeAddress (const TStringRef& str) {
26
168
TIpv6Address addr;
27
169
if (str.Size () == 4 ) {
28
170
TRawIp4 addr4;
29
171
memcpy (&addr4, str.Data (), sizeof addr4);
30
- addr = { addr4 .a , addr4 . b , addr4 . c , addr4 . d } ;
172
+ addr = addr4.ToIpAddress () ;
31
173
} else if (str.Size () == 16 ) {
32
174
TRawIp6 addr6;
33
175
memcpy (&addr6, str.Data (), sizeof addr6);
34
- addr = {ui16 (ui32 (addr6 .a1 ) << ui32 (8 ) | ui32 (addr6 .a0 )),
35
- ui16 (ui32 (addr6 .b1 ) << ui32 (8 ) | ui32 (addr6 .b0 )),
36
- ui16 (ui32 (addr6 .c1 ) << ui32 (8 ) | ui32 (addr6 .c0 )),
37
- ui16 (ui32 (addr6 .d1 ) << ui32 (8 ) | ui32 (addr6 .d0 )),
38
- ui16 (ui32 (addr6 .e1 ) << ui32 (8 ) | ui32 (addr6 .e0 )),
39
- ui16 (ui32 (addr6 .f1 ) << ui32 (8 ) | ui32 (addr6 .f0 )),
40
- ui16 (ui32 (addr6 .g1 ) << ui32 (8 ) | ui32 (addr6 .g0 )),
41
- ui16 (ui32 (addr6 .h1 ) << ui32 (8 ) | ui32 (addr6 .h0 )),
42
- };
176
+ addr = addr6.ToIpAddress ();
43
177
} else {
44
178
ythrow yexception () << " Incorrect size of input, expected "
45
179
<< " 4 or 16, got " << str.Size ();
46
180
}
47
181
return addr;
48
182
}
49
183
184
+ TIpAddressRange DeserializeSubnet (const TStringRef& str) {
185
+ TIpAddressRange range;
186
+ if (str.Size () == sizeof (TRawIp4Subnet)) {
187
+ TRawIp4Subnet subnet4;
188
+ memcpy (&subnet4, str.Data (), sizeof subnet4);
189
+ range = subnet4.ToIpRange ();
190
+ } else if (str.Size () == sizeof (TRawIp6Subnet)) {
191
+ TRawIp6Subnet subnet6;
192
+ memcpy (&subnet6, str.Data (), sizeof subnet6);
193
+ range = subnet6.ToIpRange ();
194
+ } else {
195
+ ythrow yexception () << " Invalid binary representation" ;
196
+ }
197
+ return range;
198
+ }
199
+
50
200
TString SerializeAddress (const TIpv6Address& addr) {
51
201
Y_ENSURE (addr.Type () == TIpv6Address::Ipv4 || addr.Type () == TIpv6Address::Ipv6);
52
202
TString res;
53
- ui128 x = addr ;
54
203
if (addr.Type () == TIpv6Address::Ipv4) {
55
- TRawIp4 addr4 {
56
- ui8 (x >> 24 & 0xff ),
57
- ui8 (x >> 16 & 0xff ),
58
- ui8 (x >> 8 & 0xff ),
59
- ui8 (x & 0xff )
60
- };
204
+ auto addr4 = TRawIp4::FromIpAddress (addr);
61
205
res = TString (reinterpret_cast <const char *>(&addr4), sizeof addr4);
62
206
} else if (addr.Type () == TIpv6Address::Ipv6) {
63
- TRawIp6 addr6 {
64
- ui8 (x >> 120 & 0xff ), ui8 (x >> 112 & 0xff ),
65
- ui8 (x >> 104 & 0xff ), ui8 (x >> 96 & 0xff ),
66
- ui8 (x >> 88 & 0xff ), ui8 (x >> 80 & 0xff ),
67
- ui8 (x >> 72 & 0xff ), ui8 (x >> 64 & 0xff ),
68
- ui8 (x >> 56 & 0xff ), ui8 (x >> 48 & 0xff ),
69
- ui8 (x >> 40 & 0xff ), ui8 (x >> 32 & 0xff ),
70
- ui8 (x >> 24 & 0xff ), ui8 (x >> 16 & 0xff ),
71
- ui8 (x >> 8 & 0xff ), ui8 (x & 0xff )
72
- };
207
+ auto addr6 = TRawIp6::FromIpAddress (addr);
73
208
res = TString (reinterpret_cast <const char *>(&addr6), sizeof addr6);
74
209
}
75
210
return res;
76
211
}
77
212
213
+ TString SerializeSubnet (const TIpAddressRange& range) {
214
+ TString res;
215
+ if (range.Type () == TIpv6Address::Ipv4) {
216
+ auto subnet4 = TRawIp4Subnet::FromIpRange (range);
217
+ res = TString (reinterpret_cast <const char *>(&subnet4), sizeof subnet4);
218
+ } else if (range.Type () == TIpv6Address::Ipv6) {
219
+ auto subnet6 = TRawIp6Subnet::FromIpRange (range);
220
+ res = TString (reinterpret_cast <const char *>(&subnet6), sizeof subnet6);
221
+ }
222
+ return res;
223
+ }
224
+
78
225
SIMPLE_STRICT_UDF (TFromString, TOptionalString(TAutoMapString)) {
79
226
TIpv6Address addr = TIpv6Address::FromString (args[0 ].AsStringRef ());
80
227
if (addr.Type () != TIpv6Address::Ipv4 && addr.Type () != TIpv6Address::Ipv6) {
@@ -83,10 +230,37 @@ namespace {
83
230
return valueBuilder->NewString (SerializeAddress (addr));
84
231
}
85
232
233
+ SIMPLE_STRICT_UDF (TSubnetFromString, TOptionalString(TAutoMapString)) {
234
+ TIpAddressRange range = TIpAddressRange::FromCompactString (args[0 ].AsStringRef ());
235
+ auto res = SerializeSubnet (range);
236
+ return res ? valueBuilder->NewString (res) : TUnboxedValue (TUnboxedValuePod ());
237
+ }
238
+
86
239
SIMPLE_UDF (TToString, char *(TAutoMapString)) {
87
240
return valueBuilder->NewString (DeserializeAddress (args[0 ].AsStringRef ()).ToString (false ));
88
241
}
89
242
243
+ SIMPLE_UDF (TSubnetToString, char *(TAutoMapString)) {
244
+ TStringBuilder result;
245
+ auto range = DeserializeSubnet (args[0 ].AsStringRef ());
246
+ result << (*range.Begin ()).ToString (false );
247
+ result << ' /' ;
248
+ result << ToString (GetAddressRangePrefix (range));
249
+ return valueBuilder->NewString (result);
250
+ }
251
+
252
+ SIMPLE_UDF (TSubnetMatch, bool (TAutoMapString, TAutoMapString)) {
253
+ Y_UNUSED (valueBuilder);
254
+ auto range1 = DeserializeSubnet (args[0 ].AsStringRef ());
255
+ if (args[1 ].AsStringRef ().Size () == sizeof (TRawIp4) || args[1 ].AsStringRef ().Size () == sizeof (TRawIp6)) {
256
+ auto addr2 = DeserializeAddress (args[1 ].AsStringRef ());
257
+ return TUnboxedValuePod (range1.Contains (addr2));
258
+ } else { // second argument is a whole subnet, not a single address
259
+ auto range2 = DeserializeSubnet (args[1 ].AsStringRef ());
260
+ return TUnboxedValuePod (range1.Contains (range2));
261
+ }
262
+ }
263
+
90
264
SIMPLE_STRICT_UDF (TIsIPv4, bool (TOptionalString)) {
91
265
Y_UNUSED (valueBuilder);
92
266
bool result = false ;
@@ -159,14 +333,27 @@ namespace {
159
333
return valueBuilder->NewString (SerializeAddress (beg));
160
334
}
161
335
336
+ SIMPLE_UDF (TGetSubnetByMask, char *(TAutoMapString, TAutoMapString)) {
337
+ const auto refBase = args[0 ].AsStringRef ();
338
+ const auto refMask = args[1 ].AsStringRef ();
339
+ TIpv6Address addrBase = DeserializeAddress (refBase);
340
+ TIpv6Address addrMask = DeserializeAddress (refMask);
341
+ if (addrBase.Type () != addrMask.Type ()) {
342
+ ythrow yexception () << " Base and mask differ in length" ;
343
+ }
344
+ return valueBuilder->NewString (SerializeAddress (TIpv6Address (ui128 (addrBase) & ui128 (addrMask), addrBase.Type ())));
345
+ }
346
+
162
347
#define EXPORTED_IP_BASE_UDF \
163
348
TFromString, \
349
+ TSubnetFromString, \
164
350
TToString, \
351
+ TSubnetToString, \
165
352
TIsIPv4, \
166
353
TIsIPv6, \
167
354
TIsEmbeddedIPv4, \
168
355
TConvertToIPv6, \
169
- TGetSubnet
356
+ TGetSubnet, \
357
+ TSubnetMatch, \
358
+ TGetSubnetByMask
170
359
}
171
-
172
-
0 commit comments