1 /*----------------------------------------------------------------------------
2 * bgp.c - bgp module for SendIP
4 * Copyright (C) David Ball for Project Purple, August 2001
5 *----------------------------------------------------------------------------
11 #include <sys/types.h>
12 #include <netinet/in.h>
13 #include "sendip_module.h"
17 * Roughly stolen from arpa/nameser.h
19 #define GETSHORT(ptr) (ntohs( \
20 ((u_int16_t)((u_int8_t *)(ptr))[0] << 8) | \
21 ((u_int16_t)((u_int8_t *)(ptr))[1]) \
24 #define GETLONG(ptr) (ntohl( \
25 ((u_int32_t)((u_int8_t *)(ptr))[0] << 24) | \
26 ((u_int32_t)((u_int8_t *)(ptr))[1] << 16) | \
27 ((u_int32_t)((u_int8_t *)(ptr))[2] << 8) | \
28 ((u_int32_t)((u_int8_t *)(ptr))[3]) \
31 #define PUTSHORT(ptr, s) { \
32 u_int16_t v = htons((u_int16_t)(s)); \
33 *((u_int8_t *)(ptr)) = v >> 8; \
34 *(((u_int8_t *)(ptr)) + 1) = v; \
37 #define PUTLONG(ptr, l) { \
38 u_int32_t v = htonl((u_int32_t)(l)); \
39 *((u_int8_t *)(ptr)) = v >> 24; \
40 *(((u_int8_t *)(ptr)) + 1) = v >> 16; \
41 *(((u_int8_t *)(ptr)) + 2) = v >> 8; \
42 *(((u_int8_t *)(ptr)) + 3) = v; \
47 * Defines for which parts have been modified
49 const u_int32_t BGP_MOD_LENGTH = 0x00000001;
50 const u_int32_t BGP_MOD_OPT_LEN = 0x00000002;
51 const u_int32_t BGP_MOD_WDR_LEN = 0x00000004;
52 const u_int32_t BGP_MOD_ATTR_LEN = 0x00000008;
56 * Parts of BGP messages
74 sendip_option bgp_opts[] = {
75 { "m", TRUE, "BGP Marker field (format is <hex byte>:<hex byte>:...)",
76 "FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF" },
77 { "l", TRUE, "Packet length", "Correct" },
78 { "t", TRUE, "Message Type (1 OPEN, 2 UPDATE, 3 NOTIFICATION, 4 "
81 { "o", TRUE, "Open message. Format is <version>:<AS number>:"
82 "<Hold time>:<BGP Identifier>:<Options length>",
83 "4:1:90:127.0.0.1:Correct (Any parameter can be omitted to get "
85 { "oo", TRUE, "Optional OPEN parameter. Format is <Type>:<Length>:"
86 "<Value> - value is in hex bytes separated by :s",
87 "Length may be omitted to get correct value" },
88 { "ul", TRUE, "Withdrawn routes length", "Correct" },
89 { "uw", TRUE, "Withdrawn route. Format is x.x.x.x/n:<bytes "
91 "Bytes field may be omitted to use the correct number" },
92 { "us", TRUE, "Attributes length", "Correct" },
93 { "ua", TRUE, "Attribute. Format is <flags>:<type>:"
94 "<length length (1 or 2):<length>:<data>",
95 "The length fields may be omitted to use the correct value" },
96 { "un", TRUE, "NLRI Prefix. Format is as for -buw", "As for -buw" },
97 { "n", TRUE, "Notification. Format is <code>:<subcode>:<data>",
98 "Data may be omitted for no data" },
104 const char bgp_opt_char = 'b';
108 * Gaping buffer overrun - make sure this is long enough :)
110 const u_int32_t BGP_BUFLEN = 1400;
112 /*static*/ bgp_msg_part bgp_prev_part;
113 /*static*/ u_int8_t *bgp_len_ptr = NULL;
114 /*static*/ u_int8_t *bgp_opt_len_ptr = NULL;
115 /*static*/ u_int8_t *bgp_wdr_len_ptr = NULL;
116 /*static*/ u_int8_t *bgp_attr_len_ptr = NULL;
119 sendip_data *initialize (void)
121 sendip_data *data = NULL;
124 data = malloc(sizeof(sendip_data));
127 memset(data, 0, sizeof(sendip_data));
128 data->data = malloc(BGP_BUFLEN);
129 if (data->data == NULL) {
136 memset(data->data, 0, BGP_BUFLEN);
139 memset(data->data, 0xFF, 16);
146 data->alloc_len = ptr - (u_int8_t *)data->data;
147 bgp_prev_part = BGP_HEADER;
153 static u_int32_t bgp_parse_bytes (u_int8_t *buf,
163 while (*arg_ptr != '\0' && *arg_ptr != stopc && limit > 0) {
164 *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, base);
165 if (*arg_ptr != '\0' && *arg_ptr != stopc) {
171 if (new_arg != NULL) {
179 static u_int32_t bgp_parse_nlri (u_int8_t *buf,
188 (void)bgp_parse_bytes(ptr, arg_ptr, &arg_ptr, 4, 10, '\0');
189 *buf = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10);
190 if (*arg_ptr != '\0') {
193 bytes = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10);
194 if (arg_ptr != new_arg_ptr) {
196 } else if (*buf > 0) {
197 ptr += ((*buf - 1) >> 3) + 1;
204 bool do_opt (char *optstring,
208 u_int8_t *ptr = (u_int8_t *)pack->data + pack->alloc_len;
209 u_int8_t *rem_ptr = NULL;
210 char *arg_ptr = NULL;
211 char *new_arg_ptr = NULL;
213 bool len_mod = FALSE;
216 switch (optstring[1]) {
218 rem_ptr = (u_int8_t *)pack->data;
219 (void)bgp_parse_bytes(rem_ptr, optarg, NULL, 16, 16, '\0');
222 rem_ptr = (u_int8_t *)pack->data + 16;
223 PUTSHORT(rem_ptr, (u_int16_t)strtoul(optarg, NULL, 10));
224 pack->modified |= BGP_MOD_LENGTH;
227 rem_ptr = (u_int8_t *)pack->data + 18;
228 *rem_ptr = (u_int8_t)strtoul(optarg, NULL, 0);
231 switch (optstring[2]) {
233 if (bgp_prev_part != BGP_HEADER) {
234 usage_error("Open message must come immediately "
239 *ptr = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10);
240 if (arg_ptr == new_arg_ptr) {
245 arg_ptr = new_arg_ptr;
246 if (*arg_ptr != '\0') {
249 PUTSHORT(ptr, (u_int16_t)strtoul(arg_ptr, &new_arg_ptr, 10));
250 if (arg_ptr == new_arg_ptr) {
255 arg_ptr = new_arg_ptr;
256 if (*arg_ptr != '\0') {
259 PUTSHORT(ptr, (u_int16_t)strtoul(arg_ptr, &new_arg_ptr, 10));
260 if (arg_ptr == new_arg_ptr) {
265 arg_ptr = new_arg_ptr;
266 if (*arg_ptr != '\0') {
269 (void)bgp_parse_bytes(ptr, arg_ptr, &new_arg_ptr, 4, 10, ':');
270 if (arg_ptr == new_arg_ptr) {
271 PUTLONG(ptr, 0x7F000001);
275 arg_ptr = new_arg_ptr;
276 if (*arg_ptr != '\0') {
279 *ptr = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10);
280 if (arg_ptr == new_arg_ptr) {
283 pack->modified |= BGP_MOD_OPT_LEN;
285 bgp_opt_len_ptr = ptr;
288 bgp_prev_part = BGP_OPEN;
293 if (bgp_prev_part != BGP_OPEN &&
294 bgp_prev_part != BGP_OPEN_OPT) {
295 usage_error("Open options must occur after open "
301 *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10);
302 if (*arg_ptr != '\0') {
306 *ptr = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10);
307 if (arg_ptr == new_arg_ptr) {
313 arg_ptr = new_arg_ptr;
314 if (*arg_ptr != '\0') {
318 ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFF, 16, '\0');
321 *(rem_ptr + 1) = ptr - rem_ptr;
323 if (!(pack->modified & BGP_MOD_OPT_LEN)) {
324 *bgp_opt_len_ptr += ptr - rem_ptr;
326 bgp_prev_part = BGP_OPEN_OPT;
331 fprintf(stderr, "Unrecognised BGP OPEN option: %s\n",
338 switch(optstring[2]) {
340 if (bgp_prev_part != BGP_HEADER) {
341 usage_error("Update message must come immediately "
345 bgp_wdr_len_ptr = ptr;
346 PUTSHORT(ptr, (u_int16_t)strtoul(optarg, NULL, 10));
348 pack->modified |= BGP_MOD_WDR_LEN;
349 bgp_prev_part = BGP_UPDATE_WDR_LEN;
354 if (bgp_prev_part == BGP_HEADER) {
355 bgp_wdr_len_ptr = ptr;
358 bgp_prev_part = BGP_UPDATE_WDR_LEN;
361 if (bgp_prev_part != BGP_UPDATE_WDR &&
362 bgp_prev_part != BGP_UPDATE_WDR_LEN) {
363 usage_error("Unfeasible routes must occur immediately "
364 "after header or -bul\n");
368 ptr += bgp_parse_nlri(ptr, optarg);
370 if (!(pack->modified & BGP_MOD_WDR_LEN)) {
371 PUTSHORT(bgp_wdr_len_ptr,
372 GETSHORT(bgp_wdr_len_ptr) + ptr - rem_ptr);
374 bgp_prev_part = BGP_UPDATE_WDR;
379 if (bgp_prev_part == BGP_HEADER) {
380 bgp_wdr_len_ptr = ptr;
383 bgp_prev_part = BGP_UPDATE_WDR_LEN;
386 if (bgp_prev_part != BGP_UPDATE_WDR_LEN &&
387 bgp_prev_part != BGP_UPDATE_WDR) {
388 usage_error("Path Attributes must come after "
389 "unfeasible routes (if any), "
390 "or after header\n");
393 bgp_attr_len_ptr = ptr;
394 PUTSHORT(ptr, (u_int16_t)strtoul(optarg, NULL, 10));
396 pack->modified |= BGP_MOD_ATTR_LEN;
397 bgp_prev_part = BGP_UPDATE_ATTR_LEN;
402 if (bgp_prev_part == BGP_HEADER) {
403 bgp_wdr_len_ptr = ptr;
406 bgp_prev_part = BGP_UPDATE_WDR_LEN;
409 if (bgp_prev_part == BGP_UPDATE_WDR_LEN ||
410 bgp_prev_part == BGP_UPDATE_WDR) {
411 bgp_attr_len_ptr = ptr;
414 bgp_prev_part = BGP_UPDATE_ATTR_LEN;
417 if (bgp_prev_part != BGP_UPDATE_ATTR_LEN &&
418 bgp_prev_part != BGP_UPDATE_ATTR) {
419 usage_error("Path Attributes must come after "
420 "unfeasible routes (if any), "
421 "or after header\n");
427 *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 16);
428 if (*arg_ptr != '\0') {
432 *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10);
433 if (*arg_ptr != '\0') {
437 bytes = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10);
438 if (arg_ptr != new_arg_ptr) {
445 if (*rem_ptr & 0x10) {
451 arg_ptr = new_arg_ptr;
452 if (*arg_ptr != '\0') {
457 *ptr++ = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10);
459 PUTSHORT(ptr, (u_int16_t)strtoul(arg_ptr, &new_arg_ptr, 10));
462 if (arg_ptr != new_arg_ptr) {
465 arg_ptr = new_arg_ptr;
466 if (*arg_ptr != '\0') {
471 ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFF, 16, '\0');
473 ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFFFF, 16,
479 *(rem_ptr + 2) = ptr - rem_ptr - 3;
481 PUTSHORT(rem_ptr + 2, ptr - rem_ptr - 4);
485 if (!(pack->modified & BGP_MOD_ATTR_LEN)) {
486 PUTSHORT(bgp_attr_len_ptr,
487 GETSHORT(bgp_attr_len_ptr) + ptr - rem_ptr);
489 bgp_prev_part = BGP_UPDATE_ATTR;
494 if (bgp_prev_part == BGP_HEADER) {
495 bgp_wdr_len_ptr = ptr;
498 bgp_prev_part = BGP_UPDATE_WDR_LEN;
501 if (bgp_prev_part == BGP_UPDATE_WDR_LEN ||
502 bgp_prev_part == BGP_UPDATE_WDR) {
503 bgp_attr_len_ptr = ptr;
506 bgp_prev_part = BGP_UPDATE_ATTR_LEN;
509 if (bgp_prev_part != BGP_UPDATE_ATTR_LEN &&
510 bgp_prev_part != BGP_UPDATE_ATTR &&
511 bgp_prev_part != BGP_UPDATE_NLRI) {
512 usage_error("NLRI must come after Unfeasible routes and "
513 "attributes, if any, or after header\n");
517 ptr += bgp_parse_nlri(ptr, optarg);
519 bgp_prev_part = BGP_UPDATE_NLRI;
524 fprintf(stderr, "Unrecognised BGP UPDATE option: %s\n", optstring);
530 if (bgp_prev_part != BGP_HEADER) {
531 usage_error("Notification must come immediately after header\n");
535 *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10);
536 if (*arg_ptr != '\0') {
540 *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10);
541 if (*arg_ptr != '\0') {
545 ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFFFF, 16, '\0');
547 bgp_prev_part = BGP_NOTFN;
552 fprintf(stderr, "Unrecognised BGP option: %s", optstring);
557 pack->alloc_len = ptr - (u_int8_t *)pack->data;
558 if (!(pack->modified & BGP_MOD_LENGTH)) {
559 PUTSHORT(bgp_len_ptr, pack->alloc_len);
567 bool finalize (char *hdrs,
568 sendip_data *headers[],
572 if (hdrs[strlen(hdrs) - 1] != 't') {
573 usage_error("WARNING: BGP should be carried over TCP\n");
581 return (sizeof(bgp_opts)/sizeof(sendip_option));
585 sendip_option *get_opts (void)
591 char get_optchar (void)
593 return (bgp_opt_char);