📄 ospfd_freebsd.c
字号:
/* * OSPFD routing daemon * Copyright (C) 1998 by John T. Moy * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/time.h>#include <sys/resource.h>#include <unistd.h>#include <tcl8.3/tcl.h>#include <sys/socket.h>#include <net/route.h>#include <sys/ioctl.h>#include <sys/uio.h>#include <net/if.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <arpa/inet.h>#include <errno.h>#include <signal.h>#include <syslog.h>#include "../src/ospfinc.h"#include "../src/monitor.h"#include "../src/system.h"#include "tcppkt.h"#include "freebsd.h"#include "ospfd_freebsd.h"#include <time.h>FreeBSDOspfd *ospfd_sys;char buffer[MAX_IP_PKTSIZE];// External declarationsbool get_prefix(char *prefix, InAddr &net, InMask &mask);/* Signal handlers */void timer(int){ signal(SIGALRM, timer); ospfd_sys->one_second_timer();}void quit(int){ ospfd_sys->changing_routerid = false; ospf->shutdown(10);}void reconfig(int){ signal(SIGUSR1, reconfig); ospfd_sys->read_config();}/* The main OSPF loop. Loops getting messages (packets, timer * ticks, configuration messages, etc.) and never returns * until the OSPF process is told to exit. */int main(int, char * []){ int n_fd; itimerval itim; fd_set fdset; fd_set wrset; sigset_t sigset, osigset; sys = ospfd_sys = new FreeBSDOspfd(); syslog(LOG_INFO, "Starting v%d.%d", OSPF::vmajor, OSPF::vminor); // Read configuration ospfd_sys->read_config(); if (!ospf) { syslog(LOG_ERR, "ospfd initialization failed"); exit(1); } // Set up signals signal(SIGALRM, timer); signal(SIGHUP, quit); signal(SIGTERM, quit); signal(SIGUSR1, reconfig); itim.it_interval.tv_sec = 1; itim.it_value.tv_sec = 1; itim.it_interval.tv_usec = 0; itim.it_value.tv_usec = 0; if (setitimer(ITIMER_REAL, &itim, NULL) < 0) syslog(LOG_ERR, "setitimer: %m"); sigemptyset(&sigset); sigaddset(&sigset, SIGALRM); sigaddset(&sigset, SIGHUP); sigaddset(&sigset, SIGTERM); sigaddset(&sigset, SIGUSR1); // Block signals in OSPF code sigprocmask(SIG_BLOCK, &sigset, &osigset); while (1) { int msec_tmo; int err; FD_ZERO(&fdset); FD_ZERO(&wrset); n_fd = ospfd_sys->netfd; FD_SET(ospfd_sys->netfd, &fdset); ospfd_sys->mon_fd_set(n_fd, &fdset, &wrset); if (ospfd_sys->igmpfd != -1) { FD_SET(ospfd_sys->igmpfd, &fdset); n_fd = MAX(n_fd, ospfd_sys->igmpfd); } if (ospfd_sys->rtsock != -1) { FD_SET(ospfd_sys->rtsock, &fdset); n_fd = MAX(n_fd, ospfd_sys->rtsock); } // Process any pending timers ospf->tick(); // Time till next timer firing msec_tmo = ospf->timeout(); // Flush any logging messages ospf->logflush(); // Allow signals during select sigprocmask(SIG_SETMASK, &osigset, NULL); if (msec_tmo != -1) { timeval timeout; timeout.tv_sec = msec_tmo/1000; timeout.tv_usec = (msec_tmo % 1000) * 1000; err = select(n_fd+1, &fdset, &wrset, 0, &timeout); } else err = select(n_fd+1, &fdset, &wrset, 0, 0); // Handle errors in select if (err == -1 && errno != EINTR) { syslog(LOG_ERR, "select failed %m"); exit(1); } // Check for change of Router ID ospfd_sys->process_routerid_change(); // Update elapsed time ospfd_sys->time_update(); // Block signals in OSPF code sigprocmask(SIG_BLOCK, &sigset, &osigset); // Process received data packet, if any if (err <= 0) continue; if (FD_ISSET(ospfd_sys->netfd, &fdset)) ospfd_sys->raw_receive(ospfd_sys->netfd); if (ospfd_sys->igmpfd != -1 && FD_ISSET(ospfd_sys->igmpfd, &fdset)) ospfd_sys->raw_receive(ospfd_sys->igmpfd); if (ospfd_sys->rtsock != -1 && FD_ISSET(ospfd_sys->rtsock, &fdset)) ospfd_sys->rtsock_receive(ospfd_sys->rtsock); // Process monitor queries and responses ospfd_sys->process_mon_io(&fdset, &wrset); }}/* Process packets received on a raw socket. Could * be either the OSPF socket or the IGMP socket. */void FreeBSDOspfd::raw_receive(int fd){ printf("----\nraw_receive\n"); int plen; int rcvint = -1;#if 1 unsigned int fromlen; plen = recvfrom(fd, buffer, sizeof(buffer), 0, 0, &fromlen); if (plen < 0) { syslog(LOG_ERR, "recvfrom: %m"); return; }#else msghdr msg; iovec iov; byte cmsgbuf[128]; msg.msg_name = 0; msg.msg_namelen = 0; iov.iov_len = sizeof(buffer); iov.iov_base = buffer; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = cmsgbuf; msg.msg_controllen = sizeof(cmsgbuf); plen = recvmsg(fd, &msg, 0); if (plen < 0) { syslog(LOG_ERR, "recvmsg: %m"); return; } else { cmsghdr *cmsg; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) { in_pktinfo *pktinfo; pktinfo = (in_pktinfo *) CMSG_DATA(cmsg); rcvint = pktinfo->ipi_ifindex; break; } } }#endif struct ip *iph = (struct ip *)buffer; InPkt *pkt = (InPkt *) buffer; //FreeBSD gives us the packet with the IP length in host //byte order, but ospfd expects it in network byte order. Fix it //here so we don't need to change the rest of ospfd. // //Even worse, FreeBSD modifies the IP header length to remove the IP //length to remove the IP header - add it back on. pkt->i_len = ntoh16(pkt->i_len + (iph->ip_hl*4)); // Dispatch based on IP protocol switch (pkt->i_prot) { case PROT_OSPF: printf("it's OSPF\n"); ospf->rxpkt(rcvint, pkt, plen); break; case PROT_IGMP: printf("it's IGMP\n"); ospf->rxigmp(rcvint, pkt, plen); break; case 0: ospf->mclookup(pkt->i_src, pkt->i_dest); break; default: break; }}#define RTF_NOT_FOR_US (RTF_LLINFO | RTF_LOCAL | RTF_MULTICAST \ | RTF_BROADCAST | RTF_DYNAMIC | RTF_BLACKHOLE | RTF_WASCLONED \ | RTF_STATIC )//#define RTF_NOT_FOR_US RTF_LLINFO void FreeBSDOspfd::rtsock_receive(int fd){ int plen; unsigned int fromlen; struct rt_msghdr* rtm; struct sockaddr_in *rt_sa; in_addr in; InAddr net; InMask mask; plen = recvfrom(fd, buffer, sizeof(buffer), 0, 0, &fromlen); printf("----\nrtsock_receive, plen=%d\n", plen); if (plen <= 0) { syslog(LOG_ERR, "rtsock recvfrom: %m"); return; } rtm = (struct rt_msghdr*)buffer; printf("rtm->rtm_type: %d addrs: %x\n", rtm->rtm_type, rtm->rtm_addrs); if (rtm->rtm_errno != 0) { printf("Error reading from routing socket\n"); syslog(LOG_ERR, "Error reading from routing socket: %m"); return; } switch (rtm->rtm_type) { case RTM_IFINFO: case RTM_NEWADDR: case RTM_DELADDR: //XXX we should probably be more explicit about what happened! syslog(LOG_NOTICE, "Interface changed\n"); read_config(); return; case RTM_DELETE: printf("RTM_DELETE\n"); if (rtm->rtm_pid == getpid()) { printf("pin == my pid, so I don't care about this\n"); return; } if (rtm->rtm_flags & RTF_NOT_FOR_US) { printf("not for us: rtm->rtm_flags = %x\n", rtm->rtm_flags); return; } if (!(rtm->rtm_addrs & RTA_DST)) { printf("no RTA_DST\n"); return; } //dst addr rt_sa = (struct sockaddr_in*) (((char *)rtm) + sizeof(struct rt_msghdr)); if (rt_sa->sin_family != AF_INET) { printf("rt_sa->sin_family = %d\n", rt_sa->sin_family); return; } memcpy(&in.s_addr, &rt_sa->sin_addr.s_addr, 4); rt_sa = (struct sockaddr_in*)((char *)rt_sa + rt_sa->sin_len); //skip gateway if (rtm->rtm_addrs & RTA_GATEWAY) rt_sa = (struct sockaddr_in*)((char *)rt_sa + rt_sa->sin_len); //this should be the netmask //if (rt_sa->sin_family != AF_INET) // return; memcpy(&mask, &(rt_sa->sin_addr.s_addr), 4); mask = ntoh32(mask); net = ntoh32(in.s_addr) & mask; printf("Krt Delete %s %x\n", inet_ntoa(in), mask); printf("%x,%x\n", net, mask); syslog(LOG_NOTICE, "Krt Delete %s", inet_ntoa(in)); ospf->krt_delete_notification(net, mask); break; case RTM_GET: rtsock_process(rtm); break; default: return; }}//rtsock_process parses the results of an RTM_GET message. This can be//called from rtsock_receive, or directly from upload_remnantsvoid FreeBSDOspfd::rtsock_process(struct rt_msghdr* rtm){ struct sockaddr_in *rt_dst; struct sockaddr_in *rt_mask; struct sockaddr_in *rt_genmask; struct sockaddr_in *rt_gateway; if (rtm->rtm_errno != 0) { syslog(LOG_ERR, "Error reading from routing socket: %m"); return; } // We don't want link layer info, multicast or broadcast routes, // or routes associated with directly connected interfaces. // We also don't want static routes. // The remainder are dynamic routes for remote sites, and it's these // we care about. printf("----\nrtsock_process\n"); if (rtm->rtm_flags & RTF_NOT_FOR_US) { printf("Flags indicate it's not for us (%x)\n", rtm->rtm_flags); // return; } printf("rtm_msglen = %d\n", rtm->rtm_msglen); printf("rtm_type = %d\n", rtm->rtm_type); printf("rtm_flags = %x\n", rtm->rtm_flags); printf("rtm_addrs = %x\n", rtm->rtm_addrs); printf("rtm_pid = %d\n", rtm->rtm_pid); printf("rtm_errno = %d\n", rtm->rtm_errno); printf("rtm_use = %d\n", rtm->rtm_use); rt_dst = (struct sockaddr_in*) ((char *)rtm + sizeof(struct rt_msghdr)); if (rtm->rtm_addrs & RTA_DST) { rt_gateway = (struct sockaddr_in*)((char *)rt_dst + rt_dst->sin_len); if (rt_dst->sin_family != AF_INET) { printf("Dst is not a v4 address\n"); return; } printf("rt_dst = %s\n", inet_ntoa(rt_dst->sin_addr)); } else { rt_gateway = rt_dst; } if (rtm->rtm_addrs & RTA_GATEWAY) { rt_mask = (struct sockaddr_in*)((char *)rt_gateway + rt_gateway->sin_len); if (rt_gateway->sin_family == AF_INET) { printf("rt_gateway = %s\n", inet_ntoa(rt_gateway->sin_addr)); } else { printf("rt_gateway with AF %d, len=%d\n", rt_gateway->sin_family, rt_dst->sin_len); return; } } else { rt_mask = rt_gateway; } if (rtm->rtm_addrs & RTA_NETMASK) { rt_genmask = (struct sockaddr_in*)((char *)rt_mask + rt_mask->sin_len); if (rt_mask->sin_family == AF_INET) { printf("rt_mask = %s\n", inet_ntoa(rt_mask->sin_addr)); } else { printf("rt_mask with AF %d, len=%d\n", rt_mask->sin_family, rt_dst->sin_len); printf("rt_mask = %s\n", inet_ntoa(rt_mask->sin_addr)); } } else { rt_genmask = rt_mask; } printf("We should manage this one\n");}/* Update the program's notion of time, which is in milliseconds * since program start. Wait until receiving the timer signal * to update a full second. */void FreeBSDOspfd::time_update(){ // printf("----\ntime_update\n"); timeval now; // Current idea of time int timediff; (void) gettimeofday(&now, NULL); timediff = 1000*(now.tv_sec - last_time.tv_sec); timediff += (now.tv_usec - last_time.tv_usec)/1000; if ((timediff + sys_etime.msec) < 1000) sys_etime.msec += timediff; last_time = now;}/* Signal handler for the one second timer. * Up the elapsed time to the next whole second. */void FreeBSDOspfd::one_second_timer(){ // printf("----\none_second_timer\n"); timeval now; // Current idea of time (void) gettimeofday(&now, NULL); sys_etime.sec++; sys_etime.msec = 0; last_time = now;}/* Initialize the FreeBSD interface. * Open the network interface. * Start the random number generator. */char *ospfd_log_file = "/var/log/ospfd.log";FreeBSDOspfd::FreeBSDOspfd() : OSInstance(OSPFD_MON_PORT){ printf("----\nFreeBSDOspfd\n"); rlimit rlim; next_phyint = 0; memset(phys, 0, sizeof(phys)); (void) gettimeofday(&last_time, NULL); changing_routerid = false; change_complete = false; dumping_remnants = false; // Allow core files rlim.rlim_max = RLIM_INFINITY; (void) setrlimit(RLIMIT_CORE, &rlim); // Open syslog openlog("ospfd", LOG_PID, LOG_DAEMON); // Open log file if (!(logstr = fopen(ospfd_log_file, "w"))) { syslog(LOG_ERR, "Logfile open failed: %m"); exit(1); } // Open monitoring listen socket monitor_listen(); // Open network if ((netfd = socket(AF_INET, SOCK_RAW, PROT_OSPF)) == -1) { syslog(LOG_ERR, "Network open failed: %m"); exit(1); } // We will supply headers on output int hincl = 1; setsockopt(netfd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)); //Open Routing Socket if ((rtsock = socket(PF_ROUTE, SOCK_RAW, /*AF_INET*/0)) < 0) { syslog(LOG_ERR, "Failed to open routing socket: %m"); exit(1); } rtsock_seq = 0; // Open ioctl socket if ((udpfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "Failed to open UDP socket: %m"); exit(1); } // Start random number generator srand(getpid()); // Will open multicast fd if requested to later igmpfd = -1;}/* Destructor not expected to be called during the life * of the program. */FreeBSDOspfd::~FreeBSDOspfd(){}/* TCL procedures to send configuration data to the ospfd * application. */int SetRouterID(ClientData, Tcl_Interp *, int, char *argv[]);int SendGeneral(ClientData, Tcl_Interp *, int, char *argv[]);int SendArea(ClientData, Tcl_Interp *, int, char *argv[]);int SendAggregate(ClientData, Tcl_Interp *, int, char *argv[]);int SendHost(ClientData, Tcl_Interp *, int, char *argv[]);int SendInterface(ClientData, Tcl_Interp *, int, char *argv[]);int SendVL(ClientData, Tcl_Interp *, int, char *argv[]);int SendNeighbor(ClientData, Tcl_Interp *, int, char *argv[]);int SendExtRt(ClientData, Tcl_Interp *, int, char *argv[]);int SendMD5Key(ClientData, Tcl_Interp *, int, char *argv[]);/* Read the ospfd config out of the file /etc/ospfd.conf */char *ospfd_tcl_src = "/ospfd.tcl";char *ospfd_config_file = "/etc/ospfd.conf";rtid_t new_router_id;void FreeBSDOspfd::read_config(){ printf("----\nread_config\n"); Tcl_Interp *interp; // Interpretation of config commands char sendcfg[] = "sendcfg"; int namlen; char *filename; // In process of changing router ID? if (changing_routerid) return; syslog(LOG_NOTICE, "reconfiguring"); new_router_id = 0; interp = Tcl_CreateInterp(); // Install C-language TCl commands Tcl_CreateCommand(interp, "routerid", SetRouterID, 0, 0); Tcl_CreateCommand(interp, "sendgen", SendGeneral, 0, 0); Tcl_CreateCommand(interp, "sendarea", SendArea, 0, 0); Tcl_CreateCommand(interp, "sendagg", SendAggregate, 0, 0); Tcl_CreateCommand(interp, "sendhost", SendHost, 0, 0); Tcl_CreateCommand(interp, "sendifc", SendInterface, 0, 0); Tcl_CreateCommand(interp, "sendvl", SendVL, 0, 0); Tcl_CreateCommand(interp, "sendnbr", SendNeighbor, 0, 0); Tcl_CreateCommand(interp, "sendextrt", SendExtRt, 0, 0); Tcl_CreateCommand(interp, "sendmd5", SendMD5Key, 0, 0); // Read additional TCL commands namlen = strlen(INSTALL_DIR) + strlen(ospfd_tcl_src); filename = new char[namlen+1];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -