/* * $Id: simple_bgp.c,v 2.2 2000/05/23 08:06:09 masaki Exp $ */ /* sbgp: Simple BGP4 speaker and listner. Provides way to dump * BGP routing stream to other MRT tools, as well as to save stream * to file. Can also inject BGP information into peering with real * router */ #include #include /* * GLOBALS */ io_t *IO; trace_t *default_trace; mtimer_t *timer; long last = 0; /* last time we sent a packet */ int bgp4plus_version = DEFAULT_BGP4PLUS_VERSION; int nothing = 1; char *usage = "Usage: sbgp [-01av] [-i binary_data_in_file] [-o binary_data_out_file]\n" "\t [-l log_file] [-f config_file] [-c port] [-d port] [-s src_addr]\n" "\t [-E seconds_idle_after_in_file_EOF]\n" "\t [ASmy_as] [peer_ip ASpeer_as]...\n"; /* static void sbgp_process_update (bgp_peer_t * peer, u_char * cp, u_int len); static int sbgp_peer_established (bgp_peer_t * peer); static int sbgp_process_input (); static int process_command_line_args (int argc, char *argv[]); static void io_timer (mtimer_t * timer); */ /* * Normally sbgp continues sending KEEPALIVE after input file EOF. * This is fine for most cases, but it makes it hard to run sbgp * from scrips. With * "-E seconds_idle_after_in_file_EOF" * sbgp sends KEEPALIVE for that period of time and then exits. */ static int eof_timeout; bgp_local_t *local_bgp = NULL; /* * Just write update as MRT output mesage */ static void sbgp_process_update (bgp_peer_t * peer, u_char * buf, u_int len) { u_char tmp[MAX_MSG_SIZE], *cp; cp = tmp; /* from */ BGP_PUT_SHORT (peer->gateway->AS, cp); #ifdef HAVE_IPV6 if (peer->gateway->prefix->family == AF_INET6) { memcpy (cp, prefix_tochar (peer->gateway->prefix), 16); cp += 16; } else #endif /* HAVE_IPV6 */ BGP_PUT_NETLONG (prefix_tolong (peer->gateway->prefix), cp); /* to */ BGP_PUT_SHORT (peer->local_bgp->this_as, cp); #ifdef HAVE_IPV6 if (peer->local_addr->family == AF_INET6) { memcpy (cp, prefix_tochar (peer->local_addr), 16); cp += 16; } else #endif /* HAVE_IPV6 */ BGP_PUT_NETLONG (prefix_tolong (peer->local_addr), cp); memcpy (cp, buf, len); len += (cp - tmp); #ifdef HAVE_IPV6 if (peer->gateway->prefix->family == AF_INET6) { io_write (IO, 0, (bgp4plus_version == 0) ? MSG_PROTOCOL_BGP4PLUS : MSG_PROTOCOL_BGP4PLUS_01, MSG_BGP_UPDATE, len, tmp); } else #endif /* HAVE_IPV6 */ io_write (IO, 0, MSG_PROTOCOL_BGP, MSG_BGP_UPDATE, len, tmp); } #ifdef notdef static int sbgp_peer_down (bgp_peer_t * peer) { Timer_Turn_ON (peer->timer_Start); select_delete_fd (IO->in.fd); /* this should really be in IO routines ... */ return (1); } #endif /* * called by IO. Read a packet and send it on its way via BGP */ static void sbgp_process_input (mrt_msg_t * msg) { bgp_peer_t *peer; u_char *buf; static int eof_timer = 0; /*while ((msg = (mrt_msg_t *) io_read (IO)) != NULL) { */ if ((msg = (mrt_msg_t *) io_read (IO)) == NULL) { if ((eof_timeout > 0) && (eof_timer < eof_timeout)) { trace (NORM, BGP->trace, "IO in_file EOF, timer %d/%d\n", eof_timer, eof_timeout); eof_timer += 10; Timer_Set_Time (timer, 10); Timer_Turn_ON (timer); } else { select_delete_fd (IO->in.fd); if (eof_timeout > 0) { trace (NORM, BGP->trace, "IO in_file EOF, timer %d/%d, exit\n", eof_timer, eof_timeout); exit(0); } } return; } if (msg->subtype != MSG_BGP_UPDATE) { select_enable_fd (IO->in.fd); return; } LL_Iterate (local_bgp->ll_bgp_peers, peer) { u_char *cp = (u_char *) msg->value; int length = msg->length; if (peer->state != BGPSTATE_ESTABLISHED) { continue; } if (msg->type == MSG_PROTOCOL_BGP4PLUS || msg->type == MSG_PROTOCOL_BGP4PLUS_01) { length -= (2 + 16 + 2 + 16); cp += (2 + 16 + 2 + 16); } else { length -= (2 + 4 + 2 + 4); cp += (2 + 4 + 2 + 4); } buf = NewArray (u_char, length); memcpy (buf, cp, length); bgp_send_update (peer, length, (u_char *) buf); } if (last > 0) { /* another packet at same second */ if (msg->tstamp == last) { select_enable_fd (IO->in.fd); } else { Timer_Set_Time (timer, msg->tstamp - last); Timer_Turn_ON (timer); trace (NORM, BGP->trace, "IO waiting for %d seconds\n", msg->tstamp - last); } } else { select_enable_fd (IO->in.fd); } last = msg->tstamp; /* free memory here */ Delete (msg); } static int sbgp_peer_established (bgp_peer_t * peer) { if (IO->io_input_type != IO_NONE) { select_add_fd_event ("sbgp_process_input", IO->in.fd, SELECT_READ, TRUE, BGP->schedule, sbgp_process_input, 0); /* io_set_notify (IO, 1, sbgp_process_input); */ } return (1); } /* * renable timer after x seconds so we can recreate time-based events */ static void io_timer (void) { select_enable_fd (IO->in.fd); } int main (int argc, char *argv[]) { char c; extern char *optarg; /* getopt stuff */ extern int optind; /* getopt stuff */ prefix_t *prefix; prefix_t *src_addr = NULL; int as = DEFAULT_LOCAL_AS /* must be set */; u_long id = htonl (DEFAULT_ROUTER_ID); int aflag = 0, vflag = 0; int lport = 0, cport = 0; char *ofilename = NULL, *wfilename = NULL; char *ifilename = NULL, *rfilename = NULL; char *lfilename = NULL; while ((c = getopt (argc, argv, "ar:w:hvo:i:l:s:c:d:E:")) != -1) { switch (c) { case '0': bgp4plus_version = 0; break; case '1': bgp4plus_version = 1; break; case 'a': /* accept all incoming connections */ aflag++; break; case 's': src_addr = ascii2prefix (0, optarg); break; case 'd': /* port for BGP daemon to listen on */ lport = atol (optarg); break; case 'c': /* port for BGP to connect to */ cport = atol (optarg); break; case 'o': /* out data file name */ ofilename = (char *) optarg; break; case 'w': /* out message key name */ wfilename = (char *) optarg; break; case 'i': /* in data file name */ ifilename = (char *) optarg; break; case 'r': /* in message key */ rfilename = (char *) optarg; break; case 'l': /* log file name */ lfilename = (char *) optarg; break; case 'v': /* verbose */ vflag++; break; case 'E': /* time interval after ifilename EOF */ eof_timeout = atol (optarg); break; case 'f': /* config file */ fprintf (stdout, "Config file option not yet supported"); case 'h': default: fprintf (stderr, usage); fprintf (stderr, "MRT version (%s) compiled on %s\n", MRT_VERSION, __DATE__); exit (1); break; } } init_trace (NULL, 0); default_trace = New_Trace2 ("SBGP"); if (vflag) { set_trace (default_trace, TRACE_FLAGS, TR_ALL, TRACE_LOGFILE, "stdout", NULL); set_trace_global (default_trace); } init_mrt (default_trace); init_interfaces (default_trace); init_BGP (default_trace); if (aflag) set_BGP (BGP_ACCEPT_ALL_PEERS, 1, 0); if (lport > 0) BGP->lport = lport; if (cport > 0) BGP->cport = cport; IO = New_IO (default_trace); if (ofilename) { if (io_set (IO, IO_OUTFILE, ofilename, NULL) < 0) { fprintf (stderr, "Error setting outfile %s\n", ofilename); exit (1); } } if (wfilename) { if (io_set (IO, IO_OUTMSGQ, wfilename, NULL) < 0) { fprintf (stderr, "Error setting outmsg %s\n", wfilename); exit (1); } } if (ifilename) { if (io_set (IO, IO_INFILE, ifilename, NULL) < 0) { fprintf (stderr, "Error setting infile %s\n", ifilename); exit (1); } } if (rfilename) { if (io_set (IO, IO_INMSGQ, rfilename, NULL) < 0) { fprintf (stderr, "Error setting inmsg %s\n", rfilename); exit (1); } } if (lfilename) { set_trace (default_trace, TRACE_LOGFILE, lfilename, NULL); set_trace_global (default_trace); } timer = New_Timer2 ("IO timer", 1, TIMER_ONE_SHOT, BGP->schedule, io_timer, 0); set_BGP (BGP_PEER_ESTABLISHED_FN, sbgp_peer_established, BGP_RECV_UPDATE_FN, sbgp_process_update, NULL); /* set my AS number */ if ((optind < argc) && (!strncasecmp ("AS", argv[optind], 2))) as = atoi (2 + argv[optind++]); if (id == 0) id = MRT->default_id; local_bgp = init_bgp_local (as, id); /* add peers: peer_ip [peer_AS] */ while (optind < argc) { bgp_peer_t *peer; int AS = 0; prefix = ascii2prefix (0, argv[optind++]); if (prefix == NULL) { fprintf (stderr, "Unknown host %s\n", argv[optind - 1]); exit (0); } if (optind < argc && strncasecmp ("AS", argv[optind], 2) == 0) { AS = atoi (2 + argv[optind++]); } peer = Add_BGP_Peer (local_bgp, NULL, prefix, AS, 0, BGP->trace); peer->bind_addr = src_addr; start_bgp_peer (peer); nothing = 0; } if (aflag) { init_BGP_listen (src_addr, NULL); nothing = 0; } if (nothing) { fprintf (stderr, usage); fprintf (stderr, "MRT version (%s) compiled on %s\n", MRT_VERSION, __DATE__); exit (1); } start_bgp (); mrt_main_loop (); return (1); } .