Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* Main routine of bgpd. |
3 | | * Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro |
4 | | */ |
5 | | |
6 | | #include <zebra.h> |
7 | | |
8 | | #include <pthread.h> |
9 | | #include "vector.h" |
10 | | #include "command.h" |
11 | | #include "getopt.h" |
12 | | #include "frrevent.h" |
13 | | #include <lib/version.h> |
14 | | #include "memory.h" |
15 | | #include "prefix.h" |
16 | | #include "log.h" |
17 | | #include "privs.h" |
18 | | #include "sigevent.h" |
19 | | #include "zclient.h" |
20 | | #include "routemap.h" |
21 | | #include "filter.h" |
22 | | #include "plist.h" |
23 | | #include "stream.h" |
24 | | #include "queue.h" |
25 | | #include "vrf.h" |
26 | | #include "bfd.h" |
27 | | #include "libfrr.h" |
28 | | #include "ns.h" |
29 | | |
30 | | #include "bgpd/bgpd.h" |
31 | | #include "bgp_io.h" |
32 | | #include "bgpd/bgp_attr.h" |
33 | | #include "bgpd/bgp_route.h" |
34 | | #include "bgpd/bgp_mplsvpn.h" |
35 | | #include "bgpd/bgp_aspath.h" |
36 | | #include "bgpd/bgp_dump.h" |
37 | | #include "bgpd/bgp_route.h" |
38 | | #include "bgpd/bgp_nexthop.h" |
39 | | #include "bgpd/bgp_regex.h" |
40 | | #include "bgpd/bgp_clist.h" |
41 | | #include "bgpd/bgp_debug.h" |
42 | | #include "bgpd/bgp_errors.h" |
43 | | #include "bgpd/bgp_filter.h" |
44 | | #include "bgpd/bgp_zebra.h" |
45 | | #include "bgpd/bgp_packet.h" |
46 | | #include "bgpd/bgp_keepalives.h" |
47 | | #include "bgpd/bgp_network.h" |
48 | | #include "bgpd/bgp_errors.h" |
49 | | #include "bgpd/bgp_script.h" |
50 | | #include "bgpd/bgp_evpn_mh.h" |
51 | | #include "bgpd/bgp_nht.h" |
52 | | #include "bgpd/bgp_routemap_nb.h" |
53 | | #include "bgpd/bgp_community_alias.h" |
54 | | |
55 | | #ifdef ENABLE_BGP_VNC |
56 | | #include "bgpd/rfapi/rfapi_backend.h" |
57 | | #endif |
58 | | |
59 | | /* bgpd options, we use GNU getopt library. */ |
60 | | static const struct option longopts[] = { |
61 | | {"bgp_port", required_argument, NULL, 'p'}, |
62 | | {"listenon", required_argument, NULL, 'l'}, |
63 | | {"no_kernel", no_argument, NULL, 'n'}, |
64 | | {"skip_runas", no_argument, NULL, 'S'}, |
65 | | {"ecmp", required_argument, NULL, 'e'}, |
66 | | {"int_num", required_argument, NULL, 'I'}, |
67 | | {"no_zebra", no_argument, NULL, 'Z'}, |
68 | | {"socket_size", required_argument, NULL, 's'}, |
69 | | {0}}; |
70 | | |
71 | | /* signal definitions */ |
72 | | void sighup(void); |
73 | | void sigint(void); |
74 | | void sigusr1(void); |
75 | | |
76 | | static void bgp_exit(int); |
77 | | static void bgp_vrf_terminate(void); |
78 | | |
79 | | static struct frr_signal_t bgp_signals[] = { |
80 | | { |
81 | | .signal = SIGHUP, |
82 | | .handler = &sighup, |
83 | | }, |
84 | | { |
85 | | .signal = SIGUSR1, |
86 | | .handler = &sigusr1, |
87 | | }, |
88 | | { |
89 | | .signal = SIGINT, |
90 | | .handler = &sigint, |
91 | | }, |
92 | | { |
93 | | .signal = SIGTERM, |
94 | | .handler = &sigint, |
95 | | }, |
96 | | }; |
97 | | |
98 | | /* privileges */ |
99 | | static zebra_capabilities_t _caps_p[] = {ZCAP_BIND, ZCAP_NET_RAW, |
100 | | ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN}; |
101 | | |
102 | | struct zebra_privs_t bgpd_privs = { |
103 | | #if defined(FRR_USER) && defined(FRR_GROUP) |
104 | | .user = FRR_USER, |
105 | | .group = FRR_GROUP, |
106 | | #endif |
107 | | #ifdef VTY_GROUP |
108 | | .vty_group = VTY_GROUP, |
109 | | #endif |
110 | | .caps_p = _caps_p, |
111 | | .cap_num_p = array_size(_caps_p), |
112 | | .cap_num_i = 0, |
113 | | }; |
114 | | |
115 | | static struct frr_daemon_info bgpd_di; |
116 | | |
117 | | /* SIGHUP handler. */ |
118 | | void sighup(void) |
119 | 0 | { |
120 | 0 | zlog_info("SIGHUP received, ignoring"); |
121 | |
|
122 | 0 | return; |
123 | | |
124 | | /* |
125 | | * This is turned off for the moment. There is all |
126 | | * sorts of config turned off by bgp_terminate |
127 | | * that is not setup properly again in bgp_reset. |
128 | | * I see no easy way to do this nor do I see that |
129 | | * this is a desirable way to reload config |
130 | | * given the yang work. |
131 | | */ |
132 | | /* Terminate all thread. */ |
133 | | /* |
134 | | * bgp_terminate(); |
135 | | * bgp_reset(); |
136 | | * zlog_info("bgpd restarting!"); |
137 | | |
138 | | * Reload config file. |
139 | | * vty_read_config(NULL, bgpd_di.config_file, config_default); |
140 | | */ |
141 | | /* Try to return to normal operation. */ |
142 | 0 | } |
143 | | |
144 | | /* SIGINT handler. */ |
145 | | __attribute__((__noreturn__)) void sigint(void) |
146 | 0 | { |
147 | 0 | zlog_notice("Terminating on signal"); |
148 | 0 | assert(bm->terminating == false); |
149 | 0 | bm->terminating = true; /* global flag that shutting down */ |
150 | | |
151 | | /* Disable BFD events to avoid wasting processing. */ |
152 | 0 | bfd_protocol_integration_set_shutdown(true); |
153 | |
|
154 | 0 | bgp_terminate(); |
155 | |
|
156 | 0 | bgp_exit(0); |
157 | |
|
158 | 0 | exit(0); |
159 | 0 | } |
160 | | |
161 | | /* SIGUSR1 handler. */ |
162 | | void sigusr1(void) |
163 | 0 | { |
164 | 0 | zlog_rotate(); |
165 | 0 | } |
166 | | |
167 | | /* |
168 | | Try to free up allocations we know about so that diagnostic tools such as |
169 | | valgrind are able to better illuminate leaks. |
170 | | |
171 | | Zebra route removal and protocol teardown are not meant to be done here. |
172 | | For example, "retain_mode" may be set. |
173 | | */ |
174 | | static __attribute__((__noreturn__)) void bgp_exit(int status) |
175 | 0 | { |
176 | 0 | struct bgp *bgp, *bgp_default, *bgp_evpn; |
177 | 0 | struct listnode *node, *nnode; |
178 | | |
179 | | /* it only makes sense for this to be called on a clean exit */ |
180 | 0 | assert(status == 0); |
181 | |
|
182 | 0 | frr_early_fini(); |
183 | |
|
184 | 0 | bgp_close(); |
185 | |
|
186 | 0 | bgp_default = bgp_get_default(); |
187 | 0 | bgp_evpn = bgp_get_evpn(); |
188 | | |
189 | | /* reverse bgp_master_init */ |
190 | 0 | for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { |
191 | 0 | if (bgp_default == bgp || bgp_evpn == bgp) |
192 | 0 | continue; |
193 | 0 | bgp_delete(bgp); |
194 | 0 | } |
195 | 0 | if (bgp_evpn && bgp_evpn != bgp_default) |
196 | 0 | bgp_delete(bgp_evpn); |
197 | 0 | if (bgp_default) |
198 | 0 | bgp_delete(bgp_default); |
199 | |
|
200 | 0 | bgp_evpn_mh_finish(); |
201 | 0 | bgp_l3nhg_finish(); |
202 | | |
203 | | /* reverse bgp_dump_init */ |
204 | 0 | bgp_dump_finish(); |
205 | | |
206 | | /* BGP community aliases */ |
207 | 0 | bgp_community_alias_finish(); |
208 | | |
209 | | /* reverse bgp_route_init */ |
210 | 0 | bgp_route_finish(); |
211 | | |
212 | | /* cleanup route maps */ |
213 | 0 | bgp_route_map_terminate(); |
214 | | |
215 | | /* reverse bgp_attr_init */ |
216 | 0 | bgp_attr_finish(); |
217 | | |
218 | | /* stop pthreads */ |
219 | 0 | bgp_pthreads_finish(); |
220 | | |
221 | | /* reverse access_list_init */ |
222 | 0 | access_list_add_hook(NULL); |
223 | 0 | access_list_delete_hook(NULL); |
224 | 0 | access_list_reset(); |
225 | | |
226 | | /* reverse bgp_filter_init */ |
227 | 0 | as_list_add_hook(NULL); |
228 | 0 | as_list_delete_hook(NULL); |
229 | 0 | bgp_filter_reset(); |
230 | | |
231 | | /* reverse prefix_list_init */ |
232 | 0 | prefix_list_add_hook(NULL); |
233 | 0 | prefix_list_delete_hook(NULL); |
234 | 0 | prefix_list_reset(); |
235 | | |
236 | | /* reverse community_list_init */ |
237 | 0 | community_list_terminate(bgp_clist); |
238 | |
|
239 | 0 | bgp_vrf_terminate(); |
240 | 0 | #ifdef ENABLE_BGP_VNC |
241 | 0 | vnc_zebra_destroy(); |
242 | 0 | #endif |
243 | 0 | bgp_zebra_destroy(); |
244 | |
|
245 | 0 | bf_free(bm->rd_idspace); |
246 | 0 | list_delete(&bm->bgp); |
247 | 0 | list_delete(&bm->addresses); |
248 | |
|
249 | 0 | bgp_lp_finish(); |
250 | |
|
251 | 0 | memset(bm, 0, sizeof(*bm)); |
252 | |
|
253 | 0 | frr_fini(); |
254 | 0 | exit(status); |
255 | 0 | } |
256 | | |
257 | | static int bgp_vrf_new(struct vrf *vrf) |
258 | 0 | { |
259 | 0 | if (BGP_DEBUG(zebra, ZEBRA)) |
260 | 0 | zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id); |
261 | 0 |
|
262 | 0 | return 0; |
263 | 0 | } |
264 | | |
265 | | static int bgp_vrf_delete(struct vrf *vrf) |
266 | 0 | { |
267 | 0 | if (BGP_DEBUG(zebra, ZEBRA)) |
268 | 0 | zlog_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id); |
269 | 0 |
|
270 | 0 | return 0; |
271 | 0 | } |
272 | | |
273 | | static int bgp_vrf_enable(struct vrf *vrf) |
274 | 0 | { |
275 | 0 | struct bgp *bgp; |
276 | 0 | vrf_id_t old_vrf_id; |
277 | 0 |
|
278 | 0 | if (BGP_DEBUG(zebra, ZEBRA)) |
279 | 0 | zlog_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id); |
280 | 0 |
|
281 | 0 | bgp = bgp_lookup_by_name(vrf->name); |
282 | 0 | if (bgp && bgp->vrf_id != vrf->vrf_id) { |
283 | 0 | old_vrf_id = bgp->vrf_id; |
284 | 0 | /* We have instance configured, link to VRF and make it "up". */ |
285 | 0 | bgp_vrf_link(bgp, vrf); |
286 | 0 |
|
287 | 0 | bgp_handle_socket(bgp, vrf, old_vrf_id, true); |
288 | 0 | bgp_instance_up(bgp); |
289 | 0 | vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); |
290 | 0 | vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); |
291 | 0 | vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); |
292 | 0 | vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6); |
293 | 0 | vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, |
294 | 0 | bgp_get_default(), bgp); |
295 | 0 | vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, AFI_IP, |
296 | 0 | bgp_get_default(), bgp); |
297 | 0 | vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP6, |
298 | 0 | bgp_get_default(), bgp); |
299 | 0 | vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, AFI_IP6, |
300 | 0 | bgp_get_default(), bgp); |
301 | 0 | } |
302 | 0 |
|
303 | 0 | return 0; |
304 | 0 | } |
305 | | |
306 | | static int bgp_vrf_disable(struct vrf *vrf) |
307 | 0 | { |
308 | 0 | struct bgp *bgp; |
309 | 0 |
|
310 | 0 | if (vrf->vrf_id == VRF_DEFAULT) |
311 | 0 | return 0; |
312 | 0 |
|
313 | 0 | if (BGP_DEBUG(zebra, ZEBRA)) |
314 | 0 | zlog_debug("VRF disable %s id %d", vrf->name, vrf->vrf_id); |
315 | 0 |
|
316 | 0 | bgp = bgp_lookup_by_name(vrf->name); |
317 | 0 | if (bgp) { |
318 | 0 |
|
319 | 0 | vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP); |
320 | 0 | vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6); |
321 | 0 | vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, |
322 | 0 | bgp_get_default(), bgp); |
323 | 0 | vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, AFI_IP, |
324 | 0 | bgp_get_default(), bgp); |
325 | 0 | vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP6, |
326 | 0 | bgp_get_default(), bgp); |
327 | 0 | vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, AFI_IP6, |
328 | 0 | bgp_get_default(), bgp); |
329 | 0 |
|
330 | 0 | bgp_handle_socket(bgp, vrf, VRF_UNKNOWN, false); |
331 | 0 | /* We have instance configured, unlink from VRF and make it |
332 | 0 | * "down". */ |
333 | 0 | bgp_instance_down(bgp); |
334 | 0 | bgp_vrf_unlink(bgp, vrf); |
335 | 0 | } |
336 | 0 |
|
337 | 0 | /* Note: This is a callback, the VRF will be deleted by the caller. */ |
338 | 0 | return 0; |
339 | 0 | } |
340 | | |
341 | | static void bgp_vrf_init(void) |
342 | 0 | { |
343 | 0 | vrf_init(bgp_vrf_new, bgp_vrf_enable, bgp_vrf_disable, bgp_vrf_delete); |
344 | 0 | } |
345 | | |
346 | | static void bgp_vrf_terminate(void) |
347 | 0 | { |
348 | 0 | vrf_terminate(); |
349 | 0 | } |
350 | | |
351 | | static const struct frr_yang_module_info *const bgpd_yang_modules[] = { |
352 | | &frr_filter_info, |
353 | | &frr_interface_info, |
354 | | &frr_route_map_info, |
355 | | &frr_vrf_info, |
356 | | &frr_bgp_route_map_info, |
357 | | }; |
358 | | |
359 | 2 | FRR_DAEMON_INFO(bgpd, BGP, .vty_port = BGP_VTY_PORT, |
360 | 2 | |
361 | 2 | .proghelp = "Implementation of the BGP routing protocol.", |
362 | 2 | |
363 | 2 | .signals = bgp_signals, .n_signals = array_size(bgp_signals), |
364 | 2 | |
365 | 2 | .privs = &bgpd_privs, .yang_modules = bgpd_yang_modules, |
366 | 2 | .n_yang_modules = array_size(bgpd_yang_modules), |
367 | 2 | ); |
368 | 2 | |
369 | 2 | #define DEPRECATED_OPTIONS "" |
370 | 2 | |
371 | 2 | #ifdef FUZZING |
372 | 2 | #include "lib/ringbuf.h" |
373 | 2 | |
374 | 2 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); |
375 | 2 | |
376 | 2 | static bool FuzzingInit(void) { |
377 | 1 | int bgp_port = BGP_PORT_DEFAULT; |
378 | 1 | struct list *addresses = list_new(); |
379 | 1 | int no_fib_flag = 0; |
380 | 1 | int no_zebra_flag = 0; |
381 | 1 | int skip_runas = 0; |
382 | 1 | int instance = 0; |
383 | 1 | int buffer_size = BGP_SOCKET_SNDBUF_SIZE; |
384 | 1 | struct listnode *node; |
385 | | |
386 | 1 | addresses->cmp = (int (*)(void *, void *))strcmp; |
387 | | |
388 | 1 | const char *name[] = { "bgpd" }; |
389 | | |
390 | 1 | frr_preinit(&bgpd_di, 1, (char **) name); |
391 | | |
392 | | /* Initialize basic BGP datastructures */ |
393 | 1 | bgp_master_init(frr_init_fast(), buffer_size, addresses); |
394 | 1 | bm->port = bgp_port; |
395 | 1 | bgp_option_set(BGP_OPT_NO_LISTEN); |
396 | | |
397 | 1 | bgp_option_set(BGP_OPT_NO_FIB); |
398 | 1 | bgp_option_set(BGP_OPT_NO_ZEBRA); |
399 | 1 | bgp_error_init(); |
400 | | // bgp_vrf_init(); |
401 | 1 | bgp_init((unsigned short)instance); |
402 | | |
403 | | |
404 | | /* Create a default instance and peer */ |
405 | 1 | struct bgp *b; |
406 | 1 | as_t as = 65001; |
407 | 1 | bgp_get(&b, &as, "default", BGP_INSTANCE_TYPE_DEFAULT, NULL, |
408 | 1 | ASNOTATION_UNDEFINED); |
409 | | |
410 | 1 | return true; |
411 | 1 | } |
412 | | |
413 | | /* |
414 | | * Create peer structure that we'll use as the receiver for fuzzed packets. |
415 | | * |
416 | | * state |
417 | | * BGP FSM state to create the peer in |
418 | | */ |
419 | | static struct peer *FuzzingCreatePeer(int state) |
420 | 1 | { |
421 | 1 | union sockunion su; |
422 | 1 | sockunion_init(&su); |
423 | 1 | inet_pton(AF_INET, "10.1.1.1", &su.sin.sin_addr); |
424 | 1 | su.sin.sin_family = AF_INET; |
425 | 1 | su.sin.sin_port = 2001; |
426 | 1 | struct peer *p = peer_create(&su, NULL, bgp_get_default(), 65000, 65001, |
427 | 1 | AS_UNSPECIFIED, NULL, 1, NULL); |
428 | 1 | p->bgp->rpkt_quanta = 1; |
429 | 1 | p->status = state; |
430 | 1 | p->as_type = AS_EXTERNAL; |
431 | | |
432 | | /* set all flags */ |
433 | 1 | afi_t afi; |
434 | 1 | safi_t safi; |
435 | 1 | p->cap |= 0xFFFF; |
436 | 21 | FOREACH_AFI_SAFI(afi, safi) { |
437 | 21 | SET_FLAG(p->af_cap[afi][safi], 0x3FFF); |
438 | 21 | } |
439 | | |
440 | 1 | peer_activate(p, AFI_L2VPN, SAFI_EVPN); |
441 | 1 | peer_activate(p, AFI_IP, SAFI_MPLS_VPN); |
442 | | |
443 | 1 | return p; |
444 | 1 | } |
445 | | |
446 | | static struct peer *FuzzingPeer; |
447 | | |
448 | | static bool FuzzingInitialized; |
449 | | |
450 | | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
451 | 738 | { |
452 | 738 | if (!FuzzingInitialized) { |
453 | 1 | FuzzingInit(); |
454 | 1 | FuzzingInitialized = true; |
455 | | /* See comment below */ |
456 | 1 | FuzzingPeer = FuzzingCreatePeer(Established); |
457 | 1 | } |
458 | | //make_route_maps(); |
459 | | /* |
460 | | * In the AFL standalone case, the peer will already be created for us |
461 | | * before __AFL_INIT() is called to speed things up. We can't pass it |
462 | | * as an argument because the function signature must match libFuzzer's |
463 | | * expectations, so it's saved in a global variable. Even though we'll |
464 | | * be exiting the program after each run, we still destroy the peer |
465 | | * because that increases our coverage and is likely to find memory |
466 | | * leaks when pointers are nulled that would otherwise be "in-use at |
467 | | * exit". |
468 | | * |
469 | | * In the libFuzzer case, we can either create and destroy it each time |
470 | | * to fuzz single packet rx, or we can keep the peer around, which will |
471 | | * fuzz a long lived session. Of course, as state accumulates over |
472 | | * time, memory usage will grow, which imposes some resource |
473 | | * constraints on the fuzzing host. In practice a reasonable server |
474 | | * machine with 64gb of memory or so should be able to fuzz |
475 | | * indefinitely; if bgpd consumes this much memory over time, that |
476 | | * behavior should probably be considered a bug. |
477 | | */ |
478 | 738 | struct peer *p; |
479 | 738 | #ifdef FUZZING_LIBFUZZER |
480 | | /* For non-persistent mode */ |
481 | | // p = FuzzingCreatePeer(); |
482 | | /* For persistent mode */ |
483 | 738 | p = FuzzingPeer; |
484 | | #else |
485 | | p = FuzzingPeer; |
486 | | #endif /* FUZZING_LIBFUZZER */ |
487 | | |
488 | 738 | ringbuf_reset(p->ibuf_work); |
489 | 738 | ringbuf_put(p->ibuf_work, data, size); |
490 | | |
491 | 738 | int result = 0; |
492 | 738 | unsigned char pktbuf[BGP_MAX_PACKET_SIZE]; |
493 | 738 | uint16_t pktsize = 0; |
494 | | |
495 | | /* |
496 | | * Simulate the read process done by bgp_process_reads(). |
497 | | * |
498 | | * The actual packet processing code assumes that the size field in the |
499 | | * BGP message is correct, and this check is performed by the i/o code, |
500 | | * so we need to make sure that remains true for fuzzed input. |
501 | | * |
502 | | * Also, validate_header() assumes that there is at least |
503 | | * BGP_HEADER_SIZE bytes in ibuf_work. |
504 | | */ |
505 | 738 | if ((size < BGP_HEADER_SIZE) || !validate_header(p)) { |
506 | 28 | goto done; |
507 | 28 | } |
508 | | |
509 | 710 | ringbuf_peek(p->ibuf_work, BGP_MARKER_SIZE, &pktsize, sizeof(pktsize)); |
510 | 710 | pktsize = ntohs(pktsize); |
511 | | |
512 | 710 | assert(pktsize <= p->max_packet_size); |
513 | | |
514 | 710 | if (ringbuf_remain(p->ibuf_work) >= pktsize) { |
515 | 703 | struct stream *pkt = stream_new(pktsize); |
516 | 703 | ringbuf_get(p->ibuf_work, pktbuf, pktsize); |
517 | 703 | stream_put(pkt, pktbuf, pktsize); |
518 | 703 | p->curr = pkt; |
519 | | |
520 | 703 | struct event t = {}; |
521 | 703 | t.arg = p; |
522 | 703 | bgp_process_packet(&t); |
523 | 703 | } |
524 | | |
525 | 738 | done: |
526 | | //peer_delete(p); |
527 | | |
528 | 738 | return 0; |
529 | 710 | }; |
530 | | #endif /* FUZZING */ |
531 | | |
532 | | #ifndef FUZZING_LIBFUZZER |
533 | | /* Main routine of bgpd. Treatment of argument and start bgp finite |
534 | | state machine is handled at here. */ |
535 | | int main(int argc, char **argv) |
536 | | { |
537 | | int opt; |
538 | | int tmp_port; |
539 | | |
540 | | int bgp_port = BGP_PORT_DEFAULT; |
541 | | struct list *addresses = list_new(); |
542 | | int no_fib_flag = 0; |
543 | | int no_zebra_flag = 0; |
544 | | int skip_runas = 0; |
545 | | int instance = 0; |
546 | | int buffer_size = BGP_SOCKET_SNDBUF_SIZE; |
547 | | char *address; |
548 | | struct listnode *node; |
549 | | //char *bgp_address = NULL; |
550 | | |
551 | | //addresses->cmp = (int (*)(void *, void *))strcmp; |
552 | | |
553 | | frr_preinit(&bgpd_di, argc, argv); |
554 | | |
555 | | #ifdef FUZZING |
556 | | FuzzingInit(); |
557 | | FuzzingPeer = FuzzingCreatePeer(Established); |
558 | | FuzzingInitialized = true; |
559 | | |
560 | | #ifdef __AFL_HAVE_MANUAL_CONTROL |
561 | | __AFL_INIT(); |
562 | | #endif /* __AFL_HAVE_MANUAL_CONTROL */ |
563 | | uint8_t *input; |
564 | | int r = frrfuzz_read_input(&input); |
565 | | |
566 | | if (!input) |
567 | | return 0; |
568 | | |
569 | | return LLVMFuzzerTestOneInput(input, r); |
570 | | #endif /* FUZZING */ |
571 | | |
572 | | frr_opt_add( |
573 | | "p:l:SnZe:I:s:" DEPRECATED_OPTIONS, longopts, |
574 | | " -p, --bgp_port Set BGP listen port number (0 means do not listen).\n" |
575 | | " -l, --listenon Listen on specified address (implies -n)\n" |
576 | | " -n, --no_kernel Do not install route to kernel.\n" |
577 | | " -Z, --no_zebra Do not communicate with Zebra.\n" |
578 | | " -S, --skip_runas Skip capabilities checks, and changing user and group IDs.\n" |
579 | | " -e, --ecmp Specify ECMP to use.\n" |
580 | | " -I, --int_num Set instance number (label-manager)\n" |
581 | | " -s, --socket_size Set BGP peer socket send buffer size\n"); |
582 | | |
583 | | /* Command line argument treatment. */ |
584 | | while (1) { |
585 | | opt = frr_getopt(argc, argv, 0); |
586 | | |
587 | | if (opt && opt < 128 && strchr(DEPRECATED_OPTIONS, opt)) { |
588 | | fprintf(stderr, |
589 | | "The -%c option no longer exists.\nPlease refer to the manual.\n", |
590 | | opt); |
591 | | continue; |
592 | | } |
593 | | |
594 | | if (opt == EOF) |
595 | | break; |
596 | | |
597 | | switch (opt) { |
598 | | case 0: |
599 | | break; |
600 | | case 'p': |
601 | | tmp_port = atoi(optarg); |
602 | | if (tmp_port < 0 || tmp_port > 0xffff) |
603 | | bgp_port = BGP_PORT_DEFAULT; |
604 | | else |
605 | | bgp_port = tmp_port; |
606 | | break; |
607 | | case 'e': { |
608 | | unsigned long int parsed_multipath = |
609 | | strtoul(optarg, NULL, 10); |
610 | | if (parsed_multipath == 0 |
611 | | || parsed_multipath > MULTIPATH_NUM |
612 | | || parsed_multipath > UINT_MAX) { |
613 | | flog_err( |
614 | | EC_BGP_MULTIPATH, |
615 | | "Multipath Number specified must be less than %u and greater than 0", |
616 | | MULTIPATH_NUM); |
617 | | return 1; |
618 | | } |
619 | | multipath_num = parsed_multipath; |
620 | | break; |
621 | | } |
622 | | case 'l': |
623 | | listnode_add_sort_nodup(addresses, optarg); |
624 | | break; |
625 | | case 'n': |
626 | | no_fib_flag = 1; |
627 | | break; |
628 | | case 'Z': |
629 | | no_zebra_flag = 1; |
630 | | break; |
631 | | case 'S': |
632 | | skip_runas = 1; |
633 | | break; |
634 | | case 'I': |
635 | | instance = atoi(optarg); |
636 | | if (instance > (unsigned short)-1) |
637 | | zlog_err("Instance %i out of range (0..%u)", |
638 | | instance, (unsigned short)-1); |
639 | | break; |
640 | | case 's': |
641 | | buffer_size = atoi(optarg); |
642 | | break; |
643 | | default: |
644 | | frr_help_exit(1); |
645 | | } |
646 | | } |
647 | | if (skip_runas) |
648 | | memset(&bgpd_privs, 0, sizeof(bgpd_privs)); |
649 | | |
650 | | /* BGP master init. */ |
651 | | bgp_master_init(frr_init(), buffer_size, addresses); |
652 | | bm->port = bgp_port; |
653 | | if (bgp_port == 0) |
654 | | bgp_option_set(BGP_OPT_NO_LISTEN); |
655 | | if (no_fib_flag || no_zebra_flag) |
656 | | bgp_option_set(BGP_OPT_NO_FIB); |
657 | | if (no_zebra_flag) |
658 | | bgp_option_set(BGP_OPT_NO_ZEBRA); |
659 | | bgp_error_init(); |
660 | | /* Initializations. */ |
661 | | bgp_vrf_init(); |
662 | | |
663 | | #ifdef HAVE_SCRIPTING |
664 | | bgp_script_init(); |
665 | | #endif |
666 | | |
667 | | /* BGP related initialization. */ |
668 | | bgp_init((unsigned short)instance); |
669 | | |
670 | | if (list_isempty(bm->addresses)) { |
671 | | snprintf(bgpd_di.startinfo, sizeof(bgpd_di.startinfo), |
672 | | ", bgp@<all>:%d", bm->port); |
673 | | } else { |
674 | | for (ALL_LIST_ELEMENTS_RO(bm->addresses, node, address)) |
675 | | snprintf(bgpd_di.startinfo + strlen(bgpd_di.startinfo), |
676 | | sizeof(bgpd_di.startinfo) |
677 | | - strlen(bgpd_di.startinfo), |
678 | | ", bgp@%s:%d", address, bm->port); |
679 | | } |
680 | | |
681 | | bgp_if_init(); |
682 | | |
683 | | frr_config_fork(); |
684 | | /* must be called after fork() */ |
685 | | bgp_gr_apply_running_config(); |
686 | | bgp_pthreads_run(); |
687 | | frr_run(bm->master); |
688 | | |
689 | | /* Not reached. */ |
690 | | return 0; |
691 | | } |
692 | | #endif /* FUZZING_LIBFUZZER */ |