Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/dsslib/ip_t/ip_t.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 2000-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* Phong Vo <[email protected]> *
19
* *
20
***********************************************************************/
21
#pragma prototyped
22
23
/*
24
* dss ip type library
25
*
26
* Glenn Fowler
27
* AT&T Research
28
*/
29
30
#include <dsslib.h>
31
#include <bgp.h>
32
#include <ire.h>
33
#include <itl.h>
34
#include <fv.h>
35
#include <pt.h>
36
#include <ptv.h>
37
38
#define AS16PATH_T (&types[3])
39
#define AS32PATH_T (&types[4])
40
#define IPV4ADDR_T (&types[9])
41
#define IPV6ADDR_T (&types[10])
42
#define IPV4PREFIX_T (&types[12])
43
#define IPV6PREFIX_T (&types[13])
44
45
/* XXX: some compilers choke on static foo bar[]; */
46
47
#define types _static_types
48
49
Cxtype_t types[];
50
51
#define PREFIX(a,b) ((Cxnumber_t)(a)*64+(b))
52
53
#if _typ_int64_t
54
55
#define PREFIX_ADDR(p) ((Ptaddr_t)(((Cxinteger_t)(p))>>6))
56
#define PREFIX_BITS(p) ((int)(((Cxinteger_t)(p)) & 0x3f))
57
58
#else
59
60
#define PREFIX_ADDR(p) ((Ptaddr_t)((p)/64))
61
#define PREFIX_BITS(p) prefix_bits(p)
62
63
static int
64
prefix_bits(Cxnumber_t p)
65
{
66
Cxnumber_t a;
67
unsigned long u;
68
69
u = p / 64;
70
a = u;
71
a *= 64;
72
return (int)(p - a) & 0x3f;
73
}
74
75
#endif
76
77
static Iredisc_t iredisc;
78
79
static ssize_t
80
addrv4_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
81
{
82
char* s;
83
ssize_t n;
84
85
s = fmtip4((Ptaddr_t)value->number, -1);
86
n = strlen(s);
87
if ((n + 1) > size)
88
return n + 1;
89
memcpy(buf, s, n + 1);
90
return n;
91
}
92
93
static ssize_t
94
addrv4_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
95
{
96
char* e;
97
Ptaddr_t addr;
98
99
if (strtoip4(buf, &e, &addr, NiL))
100
{
101
if (disc->errorf && !(cx->flags & CX_QUIET))
102
(*disc->errorf)(cx, disc, 1, "%-.*s: invalid ipv4 address", size, buf);
103
return -1;
104
}
105
ret->value.number = addr;
106
return e - (char*)buf;
107
}
108
109
static ssize_t
110
addrv6_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
111
{
112
char* s;
113
unsigned char* pp;
114
ssize_t n;
115
int i;
116
117
pp = (unsigned char*)value->buffer.data;
118
if (!(s = (char*)CXDETAILS(details, format, type, 0)))
119
{
120
s = pp ? fmtip6(pp, -1) : "(nil)";
121
n = strlen(s);
122
if ((n + 1) > size)
123
return n + 1;
124
memcpy(buf, s, n + 1);
125
}
126
else if (s[0] == 'C' && s[1] == 0)
127
{
128
n = 80;
129
if (size < n)
130
return n;
131
s = buf;
132
for (i = 0; i < IP6BITS; i++)
133
{
134
if (i)
135
*s++ = ',';
136
s += sfsprintf(s, 6, "0x%02x", pp ? pp[i] : 0);
137
}
138
*s = 0;
139
}
140
else
141
n = -1;
142
return n;
143
}
144
145
static ssize_t
146
addrv6_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
147
{
148
char* e;
149
unsigned char* ap;
150
unsigned char addr[IP6ADDR];
151
152
if (strtoip6(buf, &e, addr, NiL))
153
{
154
if (disc->errorf && !(cx->flags & CX_QUIET))
155
(*disc->errorf)(cx, disc, 1, "%-.*s: invalid ipv6 address", size, buf);
156
return -1;
157
}
158
if (!vm)
159
vm = Vmregion;
160
if (!(ap = vmnewof(vm, 0, unsigned char, IP6ADDR, 0)))
161
{
162
if (disc->errorf)
163
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
164
return -1;
165
}
166
memcpy(ap, &addr, sizeof(addr));
167
ret->value.buffer.data = ap;
168
ret->value.buffer.size = sizeof(*ap);
169
return e - (char*)buf;
170
}
171
172
static ssize_t
173
addr_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
174
{
175
if (disc->errorf && !(cx->flags & CX_QUIET))
176
(*disc->errorf)(cx, disc, 1, "unbound generic ip address");
177
return -1;
178
}
179
180
static ssize_t
181
addr_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
182
{
183
char* e;
184
Ptaddr_t addrv4;
185
unsigned char* ap;
186
unsigned char addrv6[IP6ADDR];
187
188
if (!strtoip4(buf, &e, &addrv4, NiL) && (e >= ((char*)buf + size) || !isalnum(*e) && *e != '.'))
189
{
190
ret->value.number = addrv4;
191
ret->type = IPV4ADDR_T;
192
return e - (char*)buf;
193
}
194
if (!strtoip6(buf, &e, addrv6, NiL) && (e >= ((char*)buf + size) || !isalnum(*e) && *e != '.'))
195
{
196
if (!vm)
197
vm = Vmregion;
198
if (!(ap = vmnewof(vm, 0, unsigned char, IP6ADDR, 0)))
199
{
200
if (disc->errorf)
201
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
202
return -1;
203
}
204
memcpy(ap, &addrv6, sizeof(addrv6));
205
ret->value.buffer.data = ap;
206
ret->value.buffer.size = sizeof(*ap);
207
ret->type = IPV6ADDR_T;
208
return e - (char*)buf;
209
}
210
if (disc->errorf && !(cx->flags & CX_QUIET))
211
(*disc->errorf)(cx, disc, 1, "%-.*s: invalid ip address", size, buf);
212
return -1;
213
}
214
215
static Cxtype_t* addr_generic[] = { (Cxtype_t*)"ipv4addr_t", (Cxtype_t*)"ipv6addr_t", 0};
216
217
static Cxtype_t* as_generic[] = { (Cxtype_t*)"as16_t", (Cxtype_t*)"as32_t", 0};
218
219
static ssize_t
220
as16path_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
221
{
222
return itl2external(cx, type, 0, 1, 1, details, &format, value, buf, size, disc);
223
}
224
225
static ssize_t
226
as16path_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
227
{
228
return itl2internal(cx, &ret->value, 0, 1, 1, buf, size, vm, disc);
229
}
230
231
static ssize_t
232
as32_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
233
{
234
unsigned long as;
235
int n;
236
237
as = value->number;
238
n = sfsprintf(buf, size, "%lu", as & 0xffff);
239
if (n >= size)
240
return n + 1;
241
return n;
242
}
243
244
static ssize_t
245
as32_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
246
{
247
char* e;
248
unsigned long as;
249
250
as = (unsigned int)strtoul(buf, &e, 10);
251
if (*e == '.')
252
{
253
as <<= 16;
254
as += (unsigned int)strtoul(e, &e, 10);
255
}
256
if (*e)
257
{
258
if (disc->errorf && !(cx->flags & CX_QUIET))
259
(*disc->errorf)(cx, disc, 1, "%-.*s: invalid as32 number", size, buf);
260
return -1;
261
}
262
ret->value.number = as;
263
return e - (char*)buf;
264
}
265
266
static ssize_t
267
as32path_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
268
{
269
return itl4external(cx, type, 0, 1, 1, details, &format, value, buf, size, disc);
270
}
271
272
static ssize_t
273
as32path_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
274
{
275
return itl4internal(cx, &ret->value, 0, 1, 1, buf, size, vm, disc);
276
}
277
278
static ssize_t
279
aspath_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
280
{
281
if (disc->errorf && !(cx->flags & CX_QUIET))
282
(*disc->errorf)(cx, disc, 1, "unbound generic as path");
283
return -1;
284
}
285
286
static ssize_t
287
aspath_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
288
{
289
register const char* b = buf;
290
register const char* e = b + size;
291
292
while (b < e && !isdigit(*b))
293
b++;
294
while (b < e && isdigit(*b))
295
b++;
296
if (b < e && *b == '.')
297
{
298
ret->type = AS32PATH_T;
299
itl4internal(cx, &ret->value, 0, 1, 1, buf, size, vm, disc);
300
}
301
ret->type = AS16PATH_T;
302
return itl2internal(cx, &ret->value, 0, 1, 1, buf, size, vm, disc);
303
}
304
305
typedef struct Path_match_s
306
{
307
Ire_t* ire16;
308
Ire_t* ire32;
309
char pat[1];
310
} Path_match_t;
311
312
static void*
313
aspath_match_comp(Cx_t* cx, Cxtype_t* sub, Cxtype_t* pat, Cxvalue_t* val, Cxdisc_t* disc)
314
{
315
Path_match_t* pm;
316
317
if (!cxisstring(pat))
318
{
319
if (disc->errorf)
320
(*disc->errorf)(NiL, disc, 2, "%s: match requires %s pattern", sub->name, cx->state->type_string->name, sub->name);
321
return 0;
322
}
323
if (!(pm = newof(0, Path_match_t, 1, strlen(val->string.data))))
324
{
325
if (disc->errorf)
326
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
327
return 0;
328
}
329
strcpy(pm->pat, val->string.data);
330
return pm;
331
}
332
333
static int
334
aspath_match_exec(Cx_t* cx, void* data, Cxtype_t* type, Cxvalue_t* val, Cxdisc_t* disc)
335
{
336
Path_match_t* pm = (Path_match_t*)data;
337
Ire_t* ire;
338
339
if (type->externalf == as32path_external)
340
{
341
if (!(ire = pm->ire32))
342
{
343
iredisc.version = IRE_VERSION;
344
iredisc.errorf = disc->errorf;
345
if (!(ire = irecomp(pm->pat, 4, 0, 1, 1, &iredisc)))
346
return -2;
347
pm->ire32 = ire;
348
}
349
}
350
else if (!(ire = pm->ire16))
351
{
352
iredisc.version = IRE_VERSION;
353
iredisc.errorf = disc->errorf;
354
if (!(ire = irecomp(pm->pat, 2, 0, 1, 1, &iredisc)))
355
return -2;
356
pm->ire16 = ire;
357
}
358
return ireexec(ire, val->buffer.data, val->buffer.size) != 0;
359
}
360
361
static int
362
aspath_match_free(Cx_t* cx, void* data, Cxdisc_t* disc)
363
{
364
Path_match_t* pm = (Path_match_t*)data;
365
366
if (pm->ire16)
367
irefree(pm->ire16);
368
if (pm->ire32)
369
irefree(pm->ire32);
370
free(pm);
371
return 0;
372
}
373
374
static ssize_t
375
cluster_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
376
{
377
return itl4external(cx, type, 0, 1, 0, details, &format, value, buf, size, disc);
378
}
379
380
static ssize_t
381
cluster_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
382
{
383
return itl4internal(cx, &ret->value, 0, 1, 0, buf, size, vm, disc);
384
}
385
386
static void*
387
cluster_match_comp(Cx_t* cx, Cxtype_t* sub, Cxtype_t* pat, Cxvalue_t* val, Cxdisc_t* disc)
388
{
389
if (!cxisstring(pat))
390
{
391
if (disc->errorf)
392
(*disc->errorf)(NiL, disc, 2, "%s: match requires %s pattern", sub->name, cx->state->type_string->name, sub->name);
393
return 0;
394
}
395
iredisc.version = IRE_VERSION;
396
iredisc.errorf = disc->errorf;
397
return irecomp(val->string.data, 4, 0, 2, 0, &iredisc);
398
}
399
400
static ssize_t
401
community_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
402
{
403
Cxformat_t* formats[2];
404
405
formats[0] = 0;
406
formats[1] = format;
407
return itl2external(cx, type, 0, 2, 0, details, formats, value, buf, size, disc);
408
}
409
410
static ssize_t
411
community_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
412
{
413
return itl2internal(cx, &ret->value, 0, 2, 0, buf, size, vm, disc);
414
}
415
416
static void*
417
community_match_comp(Cx_t* cx, Cxtype_t* sub, Cxtype_t* pat, Cxvalue_t* val, Cxdisc_t* disc)
418
{
419
if (!cxisstring(pat))
420
{
421
if (disc->errorf)
422
(*disc->errorf)(NiL, disc, 2, "%s: match requires %s pattern", sub->name, cx->state->type_string->name, sub->name);
423
return 0;
424
}
425
iredisc.version = IRE_VERSION;
426
iredisc.errorf = disc->errorf;
427
return irecomp(val->string.data, 2, 0, 2, 0, &iredisc);
428
}
429
430
static ssize_t
431
extended_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
432
{
433
Cxformat_t* formats[2];
434
435
formats[0] = 0;
436
formats[1] = format;
437
return itl1external(cx, type, 0, 8, 0, details, formats, value, buf, size, disc);
438
}
439
440
static ssize_t
441
extended_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
442
{
443
return itl1internal(cx, &ret->value, 0, 8, 0, buf, size, vm, disc);
444
}
445
446
static void*
447
extended_match_comp(Cx_t* cx, Cxtype_t* sub, Cxtype_t* pat, Cxvalue_t* val, Cxdisc_t* disc)
448
{
449
if (!cxisstring(pat))
450
{
451
if (disc->errorf)
452
(*disc->errorf)(NiL, disc, 2, "%s: match requires %s pattern", sub->name, cx->state->type_string->name, sub->name);
453
return 0;
454
}
455
iredisc.version = IRE_VERSION;
456
iredisc.errorf = disc->errorf;
457
return irecomp(val->string.data, 1, 0, 8, 0, &iredisc);
458
}
459
460
static ssize_t
461
labels_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
462
{
463
Cxformat_t* formats[2];
464
465
formats[0] = 0;
466
formats[1] = format;
467
return itl4external(cx, type, 0, 2, 0, details, formats, value, buf, size, disc);
468
}
469
470
static ssize_t
471
labels_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
472
{
473
return itl4internal(cx, &ret->value, 0, 2, 0, buf, size, vm, disc);
474
}
475
476
static void*
477
labels_match_comp(Cx_t* cx, Cxtype_t* sub, Cxtype_t* pat, Cxvalue_t* val, Cxdisc_t* disc)
478
{
479
if (!cxisstring(pat))
480
{
481
if (disc->errorf)
482
(*disc->errorf)(NiL, disc, 2, "%s: match requires %s pattern", sub->name, cx->state->type_string->name, sub->name);
483
return 0;
484
}
485
iredisc.version = IRE_VERSION;
486
iredisc.errorf = disc->errorf;
487
return irecomp(val->string.data, 2, 0, 4, 0, &iredisc);
488
}
489
490
static ssize_t
491
prefixv4_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
492
{
493
char* s;
494
ssize_t n;
495
496
if (s = (char*)CXDETAILS(details, format, type, 0))
497
s = sfprints(s, PREFIX_ADDR(value->number), PREFIX_BITS(value->number));
498
else
499
s = fmtip4(PREFIX_ADDR(value->number), PREFIX_BITS(value->number));
500
n = strlen(s);
501
if ((n + 1) > size)
502
return n + 1;
503
memcpy(buf, s, n + 1);
504
return n;
505
}
506
507
static ssize_t
508
prefixv4_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
509
{
510
char* e;
511
Ptaddr_t addr;
512
unsigned char bits;
513
514
if (strtoip4(buf, &e, &addr, &bits))
515
{
516
if (disc->errorf && !(cx->flags & CX_QUIET))
517
(*disc->errorf)(cx, disc, 1, "%-.*s: invalid ipv4 prefix", size, buf);
518
return -1;
519
}
520
ret->value.number = PREFIX(addr, bits);
521
return e - (char*)buf;
522
}
523
524
static ssize_t
525
prefixv6_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
526
{
527
char* s;
528
unsigned char* pp;
529
ssize_t n;
530
int i;
531
532
pp = (unsigned char*)value->buffer.data;
533
if (!(s = (char*)CXDETAILS(details, format, type, 0)))
534
{
535
s = pp ? fmtip6(pp, pp[IP6BITS]) : "(nil)";
536
n = strlen(s);
537
if ((n + 1) > size)
538
return n + 1;
539
memcpy(buf, s, n + 1);
540
}
541
else if (s[0] == 'C' && s[1] == 0)
542
{
543
n = 84;
544
if (size < n)
545
return n;
546
s = buf;
547
for (i = 0; i <= IP6BITS; i++)
548
{
549
if (i)
550
*s++ = ',';
551
s += sfsprintf(s, 6, "0x%02x", pp ? pp[i] : 0);
552
}
553
*s = 0;
554
}
555
else
556
n = -1;
557
return n;
558
}
559
560
static ssize_t
561
prefixv6_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
562
{
563
char* e;
564
unsigned char* pp;
565
unsigned char prefix[IP6PREFIX];
566
567
if (strtoip6(buf, &e, prefix, prefix + IP6BITS))
568
{
569
if (disc->errorf && !(cx->flags & CX_QUIET))
570
(*disc->errorf)(cx, disc, 1, "%-.*s: invalid ipv6 address", size, buf);
571
return -1;
572
}
573
if (!vm)
574
vm = Vmregion;
575
if (!(pp = vmnewof(vm, 0, unsigned char, IP6PREFIX, 0)))
576
{
577
if (disc->errorf)
578
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
579
return -1;
580
}
581
memcpy(ret->value.buffer.data = pp, prefix, IP6PREFIX);
582
ret->value.buffer.size = IP6PREFIX;
583
return e - (char*)buf;
584
}
585
586
static ssize_t
587
prefix_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
588
{
589
if (disc->errorf && !(cx->flags & CX_QUIET))
590
(*disc->errorf)(cx, disc, 1, "unbound generic ip prefix");
591
return -1;
592
}
593
594
static ssize_t
595
prefix_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
596
{
597
char* e;
598
Ptaddr_t prefixv4;
599
unsigned char* pp;
600
unsigned char prefixv6[IP6PREFIX];
601
unsigned char bits;
602
603
if (!strtoip4(buf, &e, &prefixv4, &bits) && (e >= ((char*)buf + size) || !*e || isspace(*e)))
604
{
605
ret->value.number = PREFIX(prefixv4, bits);
606
ret->type = IPV4PREFIX_T;
607
return e - (char*)buf;
608
}
609
if (!strtoip6(buf, &e, prefixv6, prefixv6 + IP6BITS) && (e >= ((char*)buf + size) || !*e || isspace(*e)))
610
{
611
if (!vm)
612
vm = Vmregion;
613
if (!(pp = vmnewof(vm, 0, unsigned char, IP6PREFIX, 0)))
614
{
615
if (disc->errorf)
616
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
617
return -1;
618
}
619
memcpy(ret->value.buffer.data = pp, prefixv6, IP6PREFIX);
620
ret->value.buffer.size = IP6PREFIX;
621
ret->type = IPV6PREFIX_T;
622
return e - (char*)buf;
623
}
624
if (disc->errorf && !(cx->flags & CX_QUIET))
625
(*disc->errorf)(cx, disc, 1, "%-.*s: invalid ip address", size, buf);
626
return -1;
627
}
628
629
static int
630
match_list_exec(Cx_t* cx, void* data, Cxtype_t* type, Cxvalue_t* val, Cxdisc_t* disc)
631
{
632
return ireexec((Ire_t*)data, val->buffer.data, val->buffer.size) != 0;
633
}
634
635
static int
636
match_list_free(Cx_t* cx, void* data, Cxdisc_t* disc)
637
{
638
return irefree((Ire_t*)data);
639
}
640
641
static Cxmatch_t match_as16path =
642
{
643
"as16path-re",
644
"Matches on this type treat a string pattern as an ire(3) 16 bit integer list regular expression. Each number in the list is a distinct token. ^ $ * + . {n,m} [N1 .. Nn] are supported, and - is equivalent to .*. Adjacent numbers may be separated by space, comma, / or _; multiple adjacent separators are ignored in the match. For example, '[!1 100]' matches all lists that contain neither 1 nor 100, and '^[!1 100]-701$' matches all lists that don't start with 1 or 100 and end with 701.",
645
CXH,
646
aspath_match_comp,
647
aspath_match_exec,
648
aspath_match_free
649
};
650
651
static Cxmatch_t match_as32path =
652
{
653
"as32path-re",
654
"Matches on this type treat a string pattern as an ire(3) 32 bit integer list regular expression. Each number in the list is a distinct token. ^ $ * + . {n,m} [N1 .. Nn] are supported, and - is equivalent to .*. Adjacent numbers may be separated by space, comma, / or _; multiple adjacent separators are ignored in the match. For example, '[!1 100]' matches all lists that contain neither 1 nor 100, and '^[!1 100]-701$' matches all lists that don't start with 1 or 100 and end with 701.",
655
CXH,
656
aspath_match_comp,
657
aspath_match_exec,
658
aspath_match_free
659
};
660
661
static Cxmatch_t match_aspath =
662
{
663
"aspath-re",
664
0,
665
CXH,
666
aspath_match_comp,
667
aspath_match_exec,
668
aspath_match_free
669
};
670
671
static Cxtype_t* aspath_generic[] = { (Cxtype_t*)"as16path_t", (Cxtype_t*)"as32path_t", 0};
672
673
static Cxmatch_t match_cluster =
674
{
675
"cluster-re",
676
"Matches on this type treat a string pattern as an ire(3) integer list regular expression. Each number in the list is a distinct token. ^ $ * + . {n,m} [N1 .. Nn] are supported, and - is equivalent to .*. Adjacent numbers may be separated by space, comma, / or _; multiple adjacent separators are ignored in the match. For example, '[!1 100]' matches all lists that contain neither 1 nor 100, and '^[!1 100]-701$' matches all lists that don't start with 1 or 100 and end with 701.",
677
CXH,
678
cluster_match_comp,
679
match_list_exec,
680
match_list_free
681
};
682
683
static Cxmatch_t match_community =
684
{
685
"community-re",
686
"Matches on this type treat a string pattern as an ire(3) integer list regular expression. Each number in the list is a distinct token. Pairs are separated by :. ^ $ * + . {n,m} [N1 .. Nn] are supported, and - is equivalent to .*. Adjacent numbers may be separated by space, comma, / or _; multiple adjacent separators are ignored in the match. If a : tuple separator is omitted then :.* is assumed. For example, '[!1 100]' matches all lists that contain neither 1 nor 100 as the first pair element, and '^[!1: :100]-701:999$' matches all lists that don't start with 1 as the first pair element or 100 as the second pair element and end with 701:999.",
687
CXH,
688
community_match_comp,
689
match_list_exec,
690
match_list_free
691
};
692
693
static Cxmatch_t match_extended =
694
{
695
"extended-re",
696
"Matches on this type treat a string pattern as an ire(3) integer list regular expression for tuples with 8 integer elements in the range 0..255. Each number in the list is a distinct token. Elements are separated by :. ^ $ * + . {n,m} [N1 .. Nn] are supported, and - is equivalent to .*. Adjacent numbers may be separated by space, comma, / or _; multiple adjacent separators are ignored in the match. If a : tuple separator is omitted then :.* is assumed. For example, '[!1 100]' matches all lists that contain neither 1 nor 100 as the first tuple element, and '^[!1: :100]-:201:199$' matches all lists that don't start with 1 as the first tuple element or 100 as the last tuple element and end with :201:199.",
697
CXH,
698
extended_match_comp,
699
match_list_exec,
700
match_list_free
701
};
702
703
static Cxmatch_t match_labels =
704
{
705
"labels-re",
706
"Matches on this type treat a string pattern as an ire(3) integer list regular expression. Each number in the list is a distinct token. Pairs are separated by :. ^ $ * + . {n,m} [N1 .. Nn] are supported, and - is equivalent to .*. Adjacent numbers may be separated by space, comma, / or _; multiple adjacent separators are ignored in the match. If a : tuple separator is omitted then :.* is assumed. For example, '[!1 100]' matches all lists that contain neither 1 nor 100 as the first pair element, and '^[!1: :100]-701:999$' matches all lists that don't start with 1 as the first pair element or 100 as the second pair element and end with 701:999.",
707
CXH,
708
labels_match_comp,
709
match_list_exec,
710
match_list_free
711
};
712
713
static Pt_t*
714
ptload(int str, Cxvalue_t* val, Ptdisc_t* ptdisc, Cxdisc_t* disc)
715
{
716
Pt_t* pt;
717
Dssmeth_t* meth;
718
Dss_t* dss;
719
Dssfile_t* ip;
720
Bgproute_t* rp;
721
char* s;
722
char* t;
723
Ptaddr_t addr;
724
unsigned char bits;
725
726
if (!(pt = ptopen(ptdisc)))
727
return 0;
728
if (!str)
729
{
730
addr = PREFIX_ADDR(val->number);
731
bits = PREFIX_BITS(val->number);
732
if (!ptinsert(pt, PTMIN(addr, bits), PTMAX(addr, bits)))
733
{
734
ptclose(pt);
735
return 0;
736
}
737
}
738
else if (*(s = val->string.data) != '<')
739
{
740
while (!strtoip4(s, &t, &addr, &bits))
741
{
742
if (!ptinsert(pt, PTMIN(addr, bits), PTMAX(addr, bits)))
743
{
744
ptclose(pt);
745
return 0;
746
}
747
s = t;
748
}
749
}
750
else if ((meth = dssmeth("bgp", disc)) && (dss = dssopen(0, 0, disc, meth)))
751
{
752
if (ip = dssfopen(dss, s + 1, NiL, DSS_FILE_READ, NiL))
753
{
754
while (rp = (Bgproute_t*)dssfread(ip))
755
if (!ptinsert(pt, PTMIN(rp->addr.v4, rp->bits), PTMAX(rp->addr.v4, rp->bits)))
756
{
757
dssfclose(ip);
758
ptclose(pt);
759
return 0;
760
}
761
dssfclose(ip);
762
}
763
dssclose(dss);
764
}
765
return pt;
766
}
767
768
typedef struct Matchdisc_s
769
{
770
Ptdisc_t ptdisc;
771
int prefix;
772
} Matchdisc_t;
773
774
static Ptv_t*
775
ptvload(int str, Cxvalue_t* val, Ptdisc_t* ptdisc, Cxdisc_t* disc)
776
{
777
Ptv_t* ptv;
778
Dssmeth_t* meth;
779
Dss_t* dss;
780
Dssfile_t* ip;
781
Bgproute_t* rp;
782
char* s;
783
char* t;
784
unsigned char* pp;
785
unsigned char prefix[IP6PREFIX];
786
787
if (!(ptv = ptvopen(ptdisc, 16)))
788
return 0;
789
if (!str)
790
{
791
pp = (unsigned char*)val->buffer.data;
792
if (!ptvinsert(ptv, ptvmin(ptv->size, ptv->r[0], pp, pp[IP6BITS]), ptvmax(ptv->size, ptv->r[1], pp, pp[IP6BITS])))
793
{
794
ptvclose(ptv);
795
return 0;
796
}
797
}
798
else if (*(s = val->buffer.data) != '<')
799
{
800
while (!strtoip6(s, &t, prefix, prefix + IP6BITS))
801
{
802
if (!ptvinsert(ptv, ptvmin(ptv->size, ptv->r[0], prefix, prefix[IP6BITS]), ptvmax(ptv->size, ptv->r[1], prefix, prefix[IP6BITS])))
803
{
804
ptvclose(ptv);
805
return 0;
806
}
807
s = t;
808
}
809
}
810
else if ((meth = dssmeth("bgp", disc)) && (dss = dssopen(0, 0, disc, meth)))
811
{
812
if (ip = dssfopen(dss, s + 1, NiL, DSS_FILE_READ, NiL))
813
{
814
while (rp = (Bgproute_t*)dssfread(ip))
815
if (!ptvinsert(ptv, ptvmin(ptv->size, ptv->r[0], rp->prefixv6, rp->prefixv6[IP6BITS]), ptvmax(ptv->size, ptv->r[1], rp->prefixv6, rp->prefixv6[IP6BITS])))
816
{
817
dssfclose(ip);
818
ptvclose(ptv);
819
return 0;
820
}
821
dssfclose(ip);
822
}
823
dssclose(dss);
824
}
825
return ptv;
826
}
827
828
typedef struct Prefix_match_s
829
{
830
Ptdisc_t ptdisc;
831
int prefix;
832
int str;
833
Pt_t* pt;
834
Ptv_t* ptv;
835
Cxvalue_t val;
836
char pat[1];
837
} Prefix_match_t;
838
839
static void*
840
prefix_match_comp(Cx_t* cx, Cxtype_t* sub, Cxtype_t* pat, Cxvalue_t* val, Cxdisc_t* disc)
841
{
842
Prefix_match_t* pm;
843
844
if (!cxisstring(pat))
845
{
846
if (disc->errorf)
847
(*disc->errorf)(NiL, disc, 2, "%s: match requires %s pattern", sub->name, cx->state->type_string->name, sub->name);
848
return 0;
849
}
850
if (!(pm = newof(0, Prefix_match_t, 1, strlen(val->string.data))))
851
{
852
if (disc->errorf)
853
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
854
return 0;
855
}
856
strcpy(pm->pat, val->string.data);
857
pm->val.string.data = pm->pat;
858
pm->str = cxisstring(pat);
859
return pm;
860
}
861
862
static int
863
prefix_match_exec(Cx_t* cx, void* data, Cxtype_t* type, Cxvalue_t* val, Cxdisc_t* disc)
864
{
865
Prefix_match_t* pm = (Prefix_match_t*)data;
866
867
if (type->externalf == addrv6_external || type->externalf == prefixv6_external)
868
{
869
if (!pm->ptv)
870
{
871
ptvinit(&pm->ptdisc);
872
pm->ptdisc.errorf = disc->errorf;
873
pm->prefix = type->externalf == prefixv6_external;
874
if (!(pm->ptv = ptvload(pm->str, &pm->val, &pm->ptdisc, disc)))
875
return -2;
876
}
877
return ptvmatch(pm->ptv, (Ptvaddr_t)val->buffer.data) != 0;
878
}
879
if (!pm->pt)
880
{
881
ptinit(&pm->ptdisc);
882
pm->ptdisc.errorf = disc->errorf;
883
pm->prefix = type->externalf == prefixv6_external;
884
if (!(pm->pt = ptload(pm->str, &pm->val, &pm->ptdisc, disc)))
885
return -1;
886
}
887
return ptmatch(pm->pt, type->externalf == prefixv4_external ? PREFIX_ADDR(val->number) : (Ptaddr_t)val->number) != 0;
888
}
889
890
static int
891
prefix_match_free(Cx_t* cx, void* data, Cxdisc_t* disc)
892
{
893
Prefix_match_t* pm = (Prefix_match_t*)data;
894
895
free(pm);
896
return 0;
897
}
898
899
static Cxmatch_t match_prefixv4 =
900
{
901
"prefix-v4-match",
902
"Matches on this type treat a string pattern as an ipv4 prefix table and test whether the subject is matched by the table. If the first character of the pattern is \b<\b then the remainder of the string is the path name of a file containing a prefix table. If the pattern is a \bipv4prefix_t\b then matches test if the subject is matched by the prefix.",
903
CXH,
904
prefix_match_comp,
905
prefix_match_exec,
906
prefix_match_free
907
};
908
909
static Cxmatch_t match_prefixv6 =
910
{
911
"prefix-v6-match",
912
"Matches on this type treat a string pattern as an ipv6 prefix table and test whether the subject is matched by the table. If the first character of the pattern is \b<\b then the remainder of the string is the path name of a file containing a prefix table. If the pattern is an \bipv6prefix_t\b then matches test if the subject is matched by the prefix.",
913
CXH,
914
prefix_match_comp,
915
prefix_match_exec,
916
prefix_match_free
917
};
918
919
static Cxmatch_t match_prefix =
920
{
921
"prefix-match",
922
0,
923
CXH,
924
prefix_match_comp,
925
prefix_match_exec,
926
prefix_match_free
927
};
928
929
static Cxtype_t* prefix_generic[] = { (Cxtype_t*)"ipv4prefix_t", (Cxtype_t*)"ipv6prefix_t", 0};
930
931
static int
932
op_match_ip4_NP(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
933
{
934
Ptaddr_t aa;
935
Ptaddr_t ba;
936
int ab;
937
int bb;
938
939
aa = PREFIX_ADDR(a->value.number);
940
ab = PREFIX_BITS(a->value.number);
941
ba = PREFIX_ADDR(b->value.number);
942
bb = PREFIX_BITS(b->value.number);
943
r->value.number = (PTMIN(aa,ab) >= PTMIN(ba,bb) && PTMAX(aa,ab) <= PTMAX(ba,bb)) == (pc->op == CX_MATCH);
944
return 0;
945
}
946
947
static int
948
op_match_ip6_NP(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
949
{
950
unsigned char* ap;
951
unsigned char* bp;
952
unsigned char r0[IP6ADDR];
953
unsigned char r1[IP6ADDR];
954
955
if (!(ap = (unsigned char*)a->value.buffer.data) || !(bp = (unsigned char*)b->value.buffer.data))
956
r->value.number = 0;
957
else
958
r->value.number = (fvcmp(16, ptvmin(16, r0, ap, ap[IP6BITS]), ptvmin(16, r1, bp, bp[IP6BITS])) >= 0 && fvcmp(16, ptvmax(16, r0, ap, ap[IP6BITS]), ptvmax(16, r1, bp, bp[IP6BITS])) <= 0) == (pc->op == CX_MATCH);
959
return 0;
960
}
961
962
static Cxcallout_t callouts[] =
963
{
964
965
CXC(CX_MATCH, "number", "ipv4prefix_t", op_match_ip4_NP, 0)
966
CXC(CX_MATCH, "buffer", "ipv6prefix_t", op_match_ip6_NP, 0)
967
968
{0}
969
970
};
971
972
/*
973
* NOTE: the *_T macros above index into this table
974
*/
975
976
Cxtype_t types[] =
977
{
978
{ "as16_t", "An unsigned 16 bit autonomous system number.", CXH, (Cxtype_t*)"number", 0, 0, 0, 0, 0, 2, 0, { 0, 0, CX_UNSIGNED|CX_INTEGER, 2, 5 }, 0 },
979
{ "as32_t", "A 32 bit autonomous system number.", CXH, (Cxtype_t*)"number", 0, as32_external, as32_internal, 0, 0, 4, 0, { 0, 0, CX_UNSIGNED|CX_INTEGER, 4, 11 }, 0 },
980
{ "as_t", 0, CXH, (Cxtype_t*)"number", 0, 0, 0, 0, 0, 0, 0, { 0, 0, CX_UNSIGNED|CX_INTEGER, 2, 5 }, 0, 0, &as_generic[0] },
981
{ "as16path_t", "A sequence of as16_t 16 bit autonomous system numbers.", CXH, (Cxtype_t*)"buffer", 0, as16path_external, as16path_internal, 0, 0, 0, 2, { "The format details string is the format character (\b1\b or \b.\b: dotted 1-byte, \bd\b: signed decimal, \bo\b: octal, \bx\b: hexadecimal, \bu\b: unsigned decimal (default)), followed by the separator string.", "u," }, &match_as16path },
982
{ "as32path_t", "A sequence of as32_t 32 bit autonomous system numbers.", CXH, (Cxtype_t*)"buffer", 0, as32path_external, as32path_internal, 0, 0, 0, 4, { "The format details string is the format character (\b1\b or \b.\b: dotted 1-byte, \b2\b: dotted 2-byte, \bd\b: signed decimal, \bo\b: octal, \bx\b: hexadecimal, \bu\b: unsigned decimal (default)), followed by the separator string.", "u," }, &match_as32path },
983
{ "aspath_t", 0, CXH, (Cxtype_t*)"buffer", 0, aspath_external, aspath_internal, 0, 0, 0, 0, { 0 }, &match_aspath, 0, &aspath_generic[0] },
984
{ "cluster_t", "A sequence of unsigned 32 bit integer cluster ids.", CXH, (Cxtype_t*)"buffer", 0, cluster_external, cluster_internal, 0, 0, 0, 4, { "The format details string is the format character (\b.\b: dotted quad, \bd\b: signed decimal, \bo\b: octal, \bx\b: hexadecimal, \bu\b: default unsigned decimal), followed by the separator string.", ".," }, &match_cluster },
985
{ "community_t", "A sequence of unsigned 16 bit integer pairs.", CXH, (Cxtype_t*)"buffer", 0, community_external, community_internal, 0, 0, 0, 2, { "The format details string is the format character (\b.\b: dotted quad, \bd\b: signed decimal, \bo\b: octal, \bx\b: hexadecimal, \bu\b: default unsigned decimal), followed by the separator string.", "u," }, &match_community },
986
{ "extended_t", "A sequence of unsigned 64 bit integer tuples.", CXH, (Cxtype_t*)"buffer", 0, extended_external, extended_internal, 0, 0, 0, 8, { "The format details string is the format character (\b.\b: dotted elements, \bd\b: signed decimal, \bo\b: octal, \bx\b: hexadecimal, \bu\b: default unsigned decimal), followed by the separator string.", "u," }, &match_extended },
987
{ "ipv4addr_t", "A dotted quad ipv4 address.", CXH, (Cxtype_t*)"number", 0, addrv4_external, addrv4_internal, 0, 0, 4, 0, { 0, 0, CX_UNSIGNED|CX_INTEGER, 4, 16 }, &match_prefixv4 },
988
{ "ipv6addr_t", "An RFC 2373 ipv6 address. The details string \"C\" lists the prefix as 16 0x%02x comma-separated values.", CXH, (Cxtype_t*)"buffer", 0, addrv6_external, addrv6_internal, 0, 0, 16, 0, { 0 }, &match_prefixv6 },
989
{ "ipaddr_t", 0, CXH, (Cxtype_t*)"number", 0, addr_external, addr_internal, 0, 0, 0, 0, { 0, 0, CX_UNSIGNED|CX_INTEGER, 4, 16 }, &match_prefix, 0, &addr_generic[0] },
990
{ "ipv4prefix_t", "/length appended to an ipv4addr_t prefix.", CXH, (Cxtype_t*)"number", 0, prefixv4_external, prefixv4_internal, 0, 0, 5, 0, { "The format details string is a \bprintf\b(3) format specification for the integer arguments \aaddress,bits\a; e.g., \b%2$u|%1$08x\b prints the decimal bits followed by the hexadecimal prefix address.", 0, CX_UNSIGNED|CX_INTEGER, 8, 19 }, &match_prefixv4 },
991
{ "ipv6prefix_t", "/length appended to an ipv6addr_t prefix. The details string \"C\" lists the prefix as 17 0x%02x comma-separated values, the first 16 being the address, and the 17th being the number of prefix bits.", CXH, (Cxtype_t*)"buffer", 0, prefixv6_external, prefixv6_internal, 0, 0, 17, 0, { 0 }, &match_prefixv6 },
992
{ "ipprefix_t", 0, CXH, (Cxtype_t*)"number", 0, prefix_external, prefix_internal, 0, 0, 0, 0, { 0 }, &match_prefix, 0, &prefix_generic[0] },
993
{ "labels_t", "A sequence of unsigned 32 bit integer pairs.", CXH, (Cxtype_t*)"buffer", 0, labels_external, labels_internal, 0, 0, 0, 8, { "The format details string is the format character (\b.\b: dotted quad, \bd\b: signed decimal, \bo\b: octal, \bx\b: hexadecimal, \bu\b: default unsigned decimal), followed by the separator string.", "u," }, &match_labels },
994
{0}
995
};
996
997
Dsslib_t dss_lib_ip_t =
998
{
999
"ip_t",
1000
"IP type support"
1001
"[-?\n@(#)$Id: dss ip type library (AT&T Research) 2008-08-18 $\n]"
1002
USAGE_LICENSE,
1003
CXH,
1004
0,
1005
0,
1006
&types[0],
1007
&callouts[0],
1008
};
1009
1010