OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / sendip / bgp.c
1 /*----------------------------------------------------------------------------
2  * bgp.c   - bgp module for SendIP
3  *
4  * Copyright (C) David Ball for Project Purple, August 2001
5  *----------------------------------------------------------------------------
6  */
7
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <netinet/in.h>
13 #include "sendip_module.h"
14
15
16 /*
17  * Roughly stolen from arpa/nameser.h
18  */
19 #define GETSHORT(ptr) (ntohs(                              \
20     ((u_int16_t)((u_int8_t *)(ptr))[0] << 8) |             \
21     ((u_int16_t)((u_int8_t *)(ptr))[1])                    \
22 ))
23
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])                    \
29 ))
30
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;                        \
35 }
36
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;                        \
43 }
44
45
46 /*
47  * Defines for which parts have been modified
48  */
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;
53
54
55 /*
56  * Parts of BGP messages
57  */
58 typedef enum {
59         BGP_HEADER,
60         BGP_OPEN,
61         BGP_OPEN_OPT,
62         BGP_UPDATE_WDR_LEN,
63         BGP_UPDATE_WDR,
64         BGP_UPDATE_ATTR_LEN,
65         BGP_UPDATE_ATTR,
66         BGP_UPDATE_NLRI,
67         BGP_NOTFN
68 } bgp_msg_part;
69
70
71 /*
72  * Options
73  */
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 "
79           "KEEPALIVE",
80           "4 (KEEPALIVE)" },
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 "
84           "the default)" },
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 "
90           "for prefix>", 
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" },
99 };
100
101 /*
102  * Option char
103  */
104 const char bgp_opt_char = 'b';
105
106
107 /*
108  * Gaping buffer overrun - make sure this is long enough :)
109  */
110 const u_int32_t  BGP_BUFLEN = 1400;
111
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;
117
118
119 sendip_data *initialize (void)
120 {
121         sendip_data *data = NULL;
122         u_int8_t    *ptr;
123         
124         data = malloc(sizeof(sendip_data));
125         
126         if (data != NULL) {
127                 memset(data, 0, sizeof(sendip_data));
128                 data->data = malloc(BGP_BUFLEN);
129                 if (data->data == NULL) {
130                         free(data);
131                         data = NULL;
132                 }
133         }
134         
135         if (data != NULL) {
136                 memset(data->data, 0, BGP_BUFLEN);
137                 ptr = data->data;
138                 
139                 memset(data->data, 0xFF, 16);
140                 ptr += 16;
141                 bgp_len_ptr = ptr;
142                 PUTSHORT(ptr, 19);
143                 ptr += 2;
144                 *ptr++ = 4;
145                 
146                 data->alloc_len = ptr - (u_int8_t *)data->data;
147                 bgp_prev_part = BGP_HEADER;
148         } 
149         return (data);
150 }
151
152
153 static u_int32_t bgp_parse_bytes (u_int8_t   *buf,
154                                   char       *arg,
155                                   char      **new_arg,
156                                   u_int32_t   limit,
157                                   int         base,
158                                   char        stopc)
159 {
160         u_int8_t *ptr = buf;
161         char     *arg_ptr = arg;
162         
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) {
166                         arg_ptr++;
167                 }
168                 limit--;
169         }
170         
171         if (new_arg != NULL) {
172                 *new_arg = arg_ptr;
173         }
174         
175         return (ptr - buf);
176 }
177
178
179 static u_int32_t bgp_parse_nlri (u_int8_t *buf,
180                                  char     *arg)
181 {
182         u_int8_t *ptr = buf;
183         char     *arg_ptr = arg;
184         char     *new_arg_ptr;
185         u_int8_t  bytes;
186         
187         ptr++;
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') {
191                 arg_ptr++;
192         }
193         bytes = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10);
194         if (arg_ptr != new_arg_ptr) {
195                 ptr += bytes;
196         } else if (*buf > 0) {
197                 ptr += ((*buf - 1) >> 3) + 1;
198         }
199
200         return (ptr - buf);
201 }
202
203
204 bool do_opt (char        *optstring,
205              char        *optarg,
206              sendip_data *pack)
207 {
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;
212         bool      rc = TRUE;
213         bool      len_mod = FALSE;
214         u_int8_t  bytes;
215
216         switch (optstring[1]) {
217         case 'm':
218                 rem_ptr = (u_int8_t *)pack->data;
219                 (void)bgp_parse_bytes(rem_ptr, optarg, NULL, 16, 16, '\0');
220                 break;
221         case 'l':
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;
225                 break;
226         case 't':
227                 rem_ptr = (u_int8_t *)pack->data + 18;
228                 *rem_ptr = (u_int8_t)strtoul(optarg, NULL, 0);
229                 break;
230         case 'o':
231                 switch (optstring[2]) {
232                 case '\0':
233                         if (bgp_prev_part != BGP_HEADER) {
234                                 usage_error("Open message must come immediately "
235                                             "after header\n");
236                                 rc = FALSE;
237                         } else {
238                                 arg_ptr = optarg;
239                                 *ptr = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10);
240                                 if (arg_ptr == new_arg_ptr) {
241                                         *ptr = 4;
242                                 }
243                                 ptr++;
244                                 
245                                 arg_ptr = new_arg_ptr;
246                                 if (*arg_ptr != '\0') {
247                                         arg_ptr++;
248                                 }
249                                 PUTSHORT(ptr, (u_int16_t)strtoul(arg_ptr, &new_arg_ptr, 10));
250                                 if (arg_ptr == new_arg_ptr) {
251                                         PUTSHORT(ptr, 1);
252                                 }
253                                 ptr += 2;
254                                 
255                                 arg_ptr = new_arg_ptr;
256                                 if (*arg_ptr != '\0') {
257                                         arg_ptr++;
258                                 }
259                                 PUTSHORT(ptr, (u_int16_t)strtoul(arg_ptr, &new_arg_ptr, 10));
260                                 if (arg_ptr == new_arg_ptr) {
261                                         PUTSHORT(ptr, 90);
262                                 }
263                                 ptr += 2;
264                                 
265                                 arg_ptr = new_arg_ptr;
266                                 if (*arg_ptr != '\0') {
267                                         arg_ptr++;
268                                 }
269                                 (void)bgp_parse_bytes(ptr, arg_ptr, &new_arg_ptr, 4, 10, ':');
270                                 if (arg_ptr == new_arg_ptr) {
271                                         PUTLONG(ptr, 0x7F000001);
272                                 }
273                                 ptr += 4;
274                                 
275                                 arg_ptr = new_arg_ptr;
276                                 if (*arg_ptr != '\0') {
277                                         arg_ptr++;
278                                 }
279                                 *ptr = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10);
280                                 if (arg_ptr == new_arg_ptr) {
281                                         *ptr = 0;
282                                 } else {
283                                         pack->modified |= BGP_MOD_OPT_LEN;
284                                 }
285                                 bgp_opt_len_ptr = ptr;
286                                 ptr++;
287                                 
288                                 bgp_prev_part = BGP_OPEN;
289                         }
290                         break;
291                 
292                 case 'o':
293                         if (bgp_prev_part != BGP_OPEN && 
294                             bgp_prev_part != BGP_OPEN_OPT) {
295                                 usage_error("Open options must occur after open "
296                                             "message\n");
297                                 rc = FALSE;
298                         } else {
299                                 rem_ptr = ptr;
300                                 arg_ptr = optarg;
301                                 *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10);
302                                 if (*arg_ptr != '\0') {
303                                         arg_ptr++;
304                                 }
305                                 
306                                 *ptr = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10);
307                                 if (arg_ptr == new_arg_ptr) {
308                                         *ptr = 0;
309                                 } else {
310                                         len_mod = TRUE;
311                                 }
312                                 ptr++;
313                                 arg_ptr = new_arg_ptr;
314                                 if (*arg_ptr != '\0') {
315                                         arg_ptr++;
316                                 }
317                                 
318                                 ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFF, 16, '\0');
319                                 
320                                 if (!len_mod) {
321                                         *(rem_ptr + 1) = ptr - rem_ptr;
322                                 }
323                                 if (!(pack->modified & BGP_MOD_OPT_LEN)) {
324                                         *bgp_opt_len_ptr += ptr - rem_ptr;
325                                 }
326                                 bgp_prev_part = BGP_OPEN_OPT;
327                         }
328                         break;
329                 
330                 default:
331                         fprintf(stderr, "Unrecognised BGP OPEN option: %s\n", 
332                                 optstring);
333                         rc = FALSE;
334                 }
335                 break;
336                 
337         case 'u':
338                 switch(optstring[2]) {
339                 case 'l':
340                         if (bgp_prev_part != BGP_HEADER) {
341                                 usage_error("Update message must come immediately "
342                                             "after header\n");
343                                 rc = FALSE;
344                         } else {
345                                 bgp_wdr_len_ptr = ptr;
346                                 PUTSHORT(ptr, (u_int16_t)strtoul(optarg, NULL, 10));
347                                 ptr += 2;
348                                 pack->modified |= BGP_MOD_WDR_LEN;
349                                 bgp_prev_part = BGP_UPDATE_WDR_LEN;
350                         }
351                         break;
352                 
353                 case 'w':
354                         if (bgp_prev_part == BGP_HEADER) {
355                                 bgp_wdr_len_ptr = ptr;
356                                 PUTSHORT(ptr, 0);
357                                 ptr += 2;
358                                 bgp_prev_part = BGP_UPDATE_WDR_LEN;
359                         }
360                 
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");
365                                 rc = FALSE;
366                         } else {
367                                 rem_ptr = ptr;
368                                 ptr += bgp_parse_nlri(ptr, optarg);
369                                 
370                                 if (!(pack->modified & BGP_MOD_WDR_LEN)) {
371                                         PUTSHORT(bgp_wdr_len_ptr, 
372                                                  GETSHORT(bgp_wdr_len_ptr) + ptr - rem_ptr);
373                                 }
374                                 bgp_prev_part = BGP_UPDATE_WDR;
375                         }
376                         break;
377                         
378                 case 's':
379                         if (bgp_prev_part == BGP_HEADER) {
380                                 bgp_wdr_len_ptr = ptr;
381                                 PUTSHORT(ptr, 0);
382                                 ptr += 2;
383                                 bgp_prev_part = BGP_UPDATE_WDR_LEN;
384                         }
385                 
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");
391                                 rc = FALSE;
392                         } else {
393                                 bgp_attr_len_ptr = ptr;
394                                 PUTSHORT(ptr, (u_int16_t)strtoul(optarg, NULL, 10));
395                                 ptr += 2;
396                                 pack->modified |= BGP_MOD_ATTR_LEN;
397                                 bgp_prev_part = BGP_UPDATE_ATTR_LEN;
398                         }
399                         break;
400                         
401                 case 'a':
402                         if (bgp_prev_part == BGP_HEADER) {
403                                 bgp_wdr_len_ptr = ptr;
404                                 PUTSHORT(ptr, 0);
405                                 ptr += 2;
406                                 bgp_prev_part = BGP_UPDATE_WDR_LEN;
407                         }
408                         
409                         if (bgp_prev_part == BGP_UPDATE_WDR_LEN || 
410                             bgp_prev_part == BGP_UPDATE_WDR) {
411                                 bgp_attr_len_ptr = ptr;
412                                 PUTSHORT(ptr, 0);
413                                 ptr += 2;
414                                 bgp_prev_part = BGP_UPDATE_ATTR_LEN;
415                         }
416                         
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");
422                                 rc = FALSE;
423                         } else {
424                                 rem_ptr = ptr;
425                                 arg_ptr = optarg;
426                                 
427                                 *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 16);
428                                 if (*arg_ptr != '\0') {
429                                         arg_ptr++;
430                                 }
431                                 
432                                 *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10);
433                                 if (*arg_ptr != '\0') {
434                                         arg_ptr++;
435                                 }
436                                 
437                                 bytes = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10);
438                                 if (arg_ptr != new_arg_ptr) {
439                                         if (bytes <= 1) {
440                                                 bytes = 1;
441                                         } else {
442                                                 bytes = 2;
443                                         }
444                                 } else {
445                                         if (*rem_ptr & 0x10) {
446                                                 bytes = 2;
447                                         } else {
448                                                 bytes = 1;
449                                         }
450                                 }
451                                 arg_ptr = new_arg_ptr;
452                                 if (*arg_ptr != '\0') {
453                                         arg_ptr++;
454                                 }
455                                 
456                                 if (bytes == 1) {
457                                         *ptr++ = (u_int8_t)strtoul(arg_ptr, &new_arg_ptr, 10);
458                                 } else {
459                                         PUTSHORT(ptr, (u_int16_t)strtoul(arg_ptr, &new_arg_ptr, 10));
460                                         ptr += 2;
461                                 }
462                                 if (arg_ptr != new_arg_ptr) {
463                                         len_mod = TRUE;
464                                 }
465                                 arg_ptr = new_arg_ptr;
466                                 if (*arg_ptr != '\0') {
467                                         arg_ptr++;
468                                 }
469
470                                 if (bytes == 1) {
471                                         ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFF, 16, '\0');
472                                 } else {
473                                         ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFFFF, 16, 
474                                                                '\0');
475                                 }
476                                 
477                                 if (!len_mod) {
478                                         if (bytes == 1) {
479                                                 *(rem_ptr + 2) = ptr - rem_ptr - 3;
480                                         } else {
481                                                 PUTSHORT(rem_ptr + 2, ptr - rem_ptr - 4);
482                                         }
483                                 }
484                                 
485                                 if (!(pack->modified & BGP_MOD_ATTR_LEN)) {
486                                         PUTSHORT(bgp_attr_len_ptr, 
487                                                  GETSHORT(bgp_attr_len_ptr) + ptr - rem_ptr);
488                                 }
489                                 bgp_prev_part = BGP_UPDATE_ATTR;
490                         }
491                         break;
492                         
493                 case 'n':
494                         if (bgp_prev_part == BGP_HEADER) {
495                                 bgp_wdr_len_ptr = ptr;
496                                 PUTSHORT(ptr, 0);
497                                 ptr += 2;
498                                 bgp_prev_part = BGP_UPDATE_WDR_LEN;
499                         }
500                         
501                         if (bgp_prev_part == BGP_UPDATE_WDR_LEN ||
502                             bgp_prev_part == BGP_UPDATE_WDR) {
503                                 bgp_attr_len_ptr = ptr;
504                                 PUTSHORT(ptr, 0);
505                                 ptr += 2;
506                                 bgp_prev_part = BGP_UPDATE_ATTR_LEN;
507                         }
508
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");
514                                 rc = FALSE;
515                         } else {
516                                 rem_ptr = ptr;
517                                 ptr += bgp_parse_nlri(ptr, optarg);
518                                 
519                                 bgp_prev_part = BGP_UPDATE_NLRI;
520                         }
521                         break;
522                         
523                 default:
524                         fprintf(stderr, "Unrecognised BGP UPDATE option: %s\n", optstring);
525                         rc = FALSE;
526                 }
527                 break;
528                 
529         case 'n':
530                 if (bgp_prev_part != BGP_HEADER) {
531                         usage_error("Notification must come immediately after header\n");
532                         rc = FALSE;
533                 } else {
534                         arg_ptr = optarg;
535                         *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10);
536                         if (*arg_ptr != '\0') {
537                                 arg_ptr++;
538                         }
539                         
540                         *ptr++ = (u_int8_t)strtoul(arg_ptr, &arg_ptr, 10);
541                         if (*arg_ptr != '\0') {
542                                 arg_ptr++;
543                         }
544                         
545                         ptr += bgp_parse_bytes(ptr, arg_ptr, NULL, 0xFFFF, 16, '\0');
546                         
547                         bgp_prev_part = BGP_NOTFN;
548                 }
549                 break;
550                 
551         default:
552                 fprintf(stderr, "Unrecognised BGP option: %s", optstring);
553                 rc = FALSE;
554         }
555         
556         if (rc) {
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);
560                 }
561         }
562         
563         return (rc);
564 }
565
566
567 bool finalize (char        *hdrs,
568                sendip_data *headers[],
569                sendip_data *data,
570                sendip_data *pack)
571 {
572         if (hdrs[strlen(hdrs) - 1] != 't') {
573                 usage_error("WARNING: BGP should be carried over TCP\n");
574         }
575         return TRUE;
576 }
577
578
579 int num_opts (void)
580 {
581         return (sizeof(bgp_opts)/sizeof(sendip_option));
582 }
583
584
585 sendip_option *get_opts (void)
586 {
587         return (bgp_opts);
588 }
589
590
591 char get_optchar (void)
592 {
593         return (bgp_opt_char);
594 }