├── CMakeLists.txt ├── README.md ├── UNLICENSE ├── feeder.cc ├── feeder.h ├── fetcher.cc ├── fetcher.h └── routefeed.cc /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.6) 2 | 3 | project (routefeed) 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -g -Wall -Wextra -Werror") 7 | 8 | find_path(LIBBGP_INCLUDE_DIR NAMES libbgp/bgp-fsm.h) 9 | find_path(CURL_INCLUDE_DIR NAMES libbgp/bgp-fsm.h) 10 | include_directories("${CURL_INCLUDE_DIR}" "${LIBBGP_INCLUDE_DIR}" "${PROJECT_SOURCE_DIR}") 11 | 12 | add_executable(routefeed feeder.cc fetcher.cc routefeed.cc) 13 | find_library(LIBBGP_LIBRARY bgp) 14 | find_library(CURL_LIBRARY curl) 15 | target_link_libraries(routefeed pthread "${CURL_LIBRARY}" "${LIBBGP_LIBRARY}") 16 | 17 | install(TARGETS routefeed DESTINATION bin) 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | cn-routefeed: China Routefeed 2 | --- 3 | 4 | `cn-routefeed` is a BGP speaker that feeds all China IPv4 delegations to peer. The delegation information is fetched from APNIC (from ). `cn-routefeed` might be useful if you are trying to set up special routing for IPv4 routes that are based in China. 5 | 6 | If APNIC changed the URL of delegation information file in the future, you could change that URL on line 5 of `fetcher.cc`. 7 | 8 | ### Installation 9 | 10 | `cn-routefeed` need the following build dependencies: 11 | 12 | - g++ (or any other c++ compiler) 13 | - [libbgp](https://github.com/Nat-Lab/libbgp) 14 | - libcurl 15 | - cmake (optional) 16 | 17 | For libbgp, please follow the installation instruction on the [project page](https://github.com/Nat-Lab/libbgp). For other build dependencies, you can install them on a Debian-based Linux distribution with the following `apt` command: 18 | 19 | ``` 20 | # apt install g++ libcurl4-nss-dev cmake 21 | ``` 22 | 23 | Once you have the dependencies installed, use the following commands to build `routefeed`: 24 | 25 | ``` 26 | $ git clone https://github.com/nat-lab/cn-routefeed 27 | $ cd cn-routefeed 28 | $ mkdir build 29 | $ cd build 30 | $ cmake ../ 31 | $ make 32 | ``` 33 | 34 | Or, if you are not into the `cmake` kind of thing, you can build the project with: 35 | 36 | ``` 37 | $ g++ *.cc -lbgp -lcurl -lpthread -oroutefeed 38 | ``` 39 | 40 | It should work on most of the cases. 41 | 42 | ### Usage 43 | 44 | `cn-routefeed` is a simple tool. The command-line help is pretty self-explanatory: 45 | 46 | ``` 47 | usage: routefeed [-l HOST] [-p PORT] [-t INTERVAL] -a ASN -i BGP_ID -n NEXTHOP 48 | [-c CONFIG] [-v] 49 | 50 | cn-routefeed is a BGP speaker that feeds all China IPv4 delegations to peer. 51 | Delegation information is fetch from APNIC. 52 | 53 | required arguments: 54 | -a ASN Local ASN of the BGP speaker. 55 | -i BGP_ID BGP ID (Router ID) of the BGP speaker. 56 | -n NEXTHOP Nexthop to use when sending routes. 57 | 58 | optional arguments: 59 | -l HOST IP address to bind the BGP speaker on. (default: 0.0.0.0) 60 | -p PORT TCP port number to bind the BGP speaker on. (default: 179) 61 | -t INTERVAL Time in second to wait between fetching update from APNIC. 62 | (default: 86400) 63 | -c CONFIG Read command line arguments from file. 64 | -v Enable debug mode (verbose). 65 | ``` 66 | 67 | For example, you can start a feeder with the following command: 68 | 69 | ``` 70 | # routefeed -a 65000 -i 172.16.0.1 -n 172.16.0.1 71 | ``` 72 | 73 | This command starts a BGP speaker on `0.0.0.0:179`, with ASN 65000. It accepts peer with any ASN and will feed the peer with routes using `172.16.0.1` as nexthop. 74 | 75 | ### License 76 | 77 | UNLICENSE -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /feeder.cc: -------------------------------------------------------------------------------- 1 | #include "feeder.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace cnrf { 10 | 11 | Feeder::Feeder(const FeederConfiguration &feder_config) : 12 | rib(&logger), fetcher(&rib, &bus, feder_config.nexthop) { 13 | logger.setLogLevel(feder_config.verbose ? libbgp::DEBUG : libbgp::INFO); 14 | fsm_logger.setLogLevel(feder_config.verbose ? libbgp::DEBUG : libbgp::WARN); 15 | running = false; 16 | config_template.asn = feder_config.my_asn; 17 | config_template.default_nexthop4 = feder_config.nexthop; 18 | config_template.forced_default_nexthop4 = true; 19 | config_template.in_filters4 = libbgp::BgpFilterRules(libbgp::REJECT); 20 | config_template.log_handler = &fsm_logger; 21 | config_template.peer_asn = 0; 22 | config_template.rib4 = &rib; 23 | config_template.router_id = feder_config.bgp_id; 24 | this->update_interval = feder_config.update_interval; 25 | this->host = feder_config.host; 26 | this->port = feder_config.port; 27 | } 28 | 29 | bool Feeder::start() { 30 | if (running) return false; 31 | 32 | fd_sock = -1; 33 | struct sockaddr_in server_addr; 34 | 35 | memset(&server_addr, 0, sizeof(server_addr)); 36 | server_addr.sin_family = AF_INET; 37 | server_addr.sin_addr.s_addr = host; 38 | server_addr.sin_port = htons(port); 39 | 40 | fd_sock = socket(AF_INET, SOCK_STREAM, 0); 41 | 42 | if (fd_sock < 0) { 43 | logger.log(libbgp::FATAL, "Feeder::start: socket(): %s\n", strerror(errno)); 44 | return false; 45 | } 46 | 47 | int bind_ret = bind(fd_sock, (struct sockaddr *) &server_addr, sizeof(server_addr)); 48 | 49 | if (bind_ret < 0) { 50 | logger.log(libbgp::FATAL, "Feeder::start: bind(): %s\n", strerror(errno)); 51 | close(fd_sock); 52 | return false; 53 | } 54 | 55 | int listen_ret = listen(fd_sock, 1); 56 | 57 | if (listen_ret < 0) { 58 | logger.log(libbgp::FATAL, "Feeder::start: listen(): %s\n", strerror(errno)); 59 | close(fd_sock); 60 | return false; 61 | } 62 | 63 | logger.log(libbgp::INFO, "Feeder::start: init rib...\n"); 64 | 65 | fetcher.updateRib(); 66 | 67 | logger.log(libbgp::INFO, "Feeder::start: ready.\n"); 68 | 69 | running = true; 70 | 71 | threads.push_back(std::thread (&Feeder::tick, this)); 72 | threads.push_back(std::thread (&Feeder::handleAccept, this)); 73 | 74 | return true; 75 | } 76 | 77 | void Feeder::stop() { 78 | if (!running) return; 79 | running = false; 80 | logger.log(libbgp::INFO, "Feeder::stop: shutting down...\n"); 81 | int fd_sock_temp = fd_sock; 82 | fd_sock = -1; 83 | shutdown(fd_sock_temp, SHUT_RDWR); 84 | close(fd_sock_temp); 85 | for (libbgp::BgpFsm *fsm : fsms) { 86 | fsm->stop(); 87 | } 88 | //for (int fd : client_fds) shutdown(fd, SHUT_RDWR); 89 | for (std::thread &t : threads) { 90 | t.detach(); 91 | } 92 | } 93 | 94 | void Feeder::join() { 95 | for (std::thread &t : threads) { 96 | if (t.joinable()) t.join(); 97 | } 98 | } 99 | 100 | void Feeder::tick() { 101 | uint32_t time = 1; 102 | 103 | while (running) { 104 | time %= update_interval; 105 | if (time == 0) fetcher.updateRib(); 106 | time++; 107 | list_mtx.lock(); 108 | for (std::vector::const_iterator iter = fsms.begin(); iter != fsms.end();) { 109 | libbgp::BgpState s = (*iter)->getState(); 110 | if (s == libbgp::IDLE || s == libbgp::BROKEN) { 111 | fsms.erase(iter); 112 | continue; 113 | } 114 | (*iter)->tick(); 115 | iter++; 116 | } 117 | list_mtx.unlock(); 118 | std::this_thread::sleep_for(std::chrono::seconds(1)); 119 | } 120 | } 121 | 122 | void Feeder::handleSession(const char *peer_addr, int fd) { 123 | char *p_addr = strdup(peer_addr); 124 | uint8_t this_buffer[4096]; 125 | libbgp::FdOutHandler this_out(fd); 126 | libbgp::BgpConfig this_config(config_template); 127 | this_config.out_handler = &this_out; 128 | libbgp::BgpFsm this_fsm(this_config); 129 | 130 | ssize_t read_ret = -1; 131 | 132 | list_mtx.lock(); 133 | //client_fds.push_back(fd); 134 | fsms.push_back(&this_fsm); 135 | list_mtx.unlock(); 136 | 137 | while ((read_ret = read(fd, this_buffer, 4096)) > 0) { 138 | int fsm_ret = this_fsm.run(this_buffer, (size_t) read_ret); 139 | if (fsm_ret <= 0 || fsm_ret == 2) break; 140 | } 141 | 142 | this_fsm.resetHard(); 143 | 144 | list_mtx.lock(); 145 | /*for (std::vector::const_iterator iter = client_fds.begin(); iter != client_fds.end(); iter++) { 146 | if (*iter == fd) { 147 | client_fds.erase(iter); 148 | break; 149 | } 150 | }*/ 151 | for (std::vector::const_iterator iter = fsms.begin(); iter != fsms.end(); iter++) { 152 | if (*iter == &this_fsm) { 153 | fsms.erase(iter); 154 | break; 155 | } 156 | } 157 | list_mtx.unlock(); 158 | close(fd); 159 | logger.log(libbgp::INFO, "Feeder::handleSession: session with AS%u (%s) closed.\n", this_fsm.getPeerAsn(), p_addr); 160 | free(p_addr); 161 | } 162 | 163 | void Feeder::handleAccept() { 164 | struct sockaddr_in client_addr; 165 | socklen_t caddr_len = sizeof(client_addr); 166 | char client_addr_str[INET_ADDRSTRLEN]; 167 | 168 | while (running) { 169 | int fd_conn = accept(fd_sock, (struct sockaddr *) &client_addr, &caddr_len); 170 | 171 | if (fd_sock <= 0) { 172 | if (running) { 173 | logger.log(libbgp::FATAL, "Feeder::handleAccept: socket unexpectedly closed, stopping.\n"); 174 | close(fd_sock); 175 | stop(); 176 | return; 177 | } 178 | break; 179 | } 180 | 181 | if (fd_conn < 0) { 182 | logger.log(libbgp::ERROR, "Feeder::handleAccept: accept(): %s\n", strerror(errno)); 183 | close(fd_conn); 184 | continue; 185 | } 186 | 187 | inet_ntop(AF_INET, &(client_addr.sin_addr), client_addr_str, INET_ADDRSTRLEN); 188 | 189 | logger.log(libbgp::INFO, "Feeder::handleAccept: new client from %s.\n", client_addr_str); 190 | threads.push_back(std::thread (&Feeder::handleSession, this, client_addr_str, fd_conn)); 191 | } 192 | 193 | logger.log(libbgp::INFO, "Feeder::handleAccept: accept handler stopped.\n"); 194 | if (fd_sock > 0) close(fd_sock); 195 | } 196 | 197 | } -------------------------------------------------------------------------------- /feeder.h: -------------------------------------------------------------------------------- 1 | #ifndef FEEDER_H 2 | #define FEEDER_H 3 | #include "fetcher.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace cnrf { 11 | 12 | struct FeederConfiguration { 13 | uint32_t my_asn = 0; 14 | uint32_t bgp_id = 0; 15 | uint32_t nexthop = 0; 16 | uint32_t update_interval = 86400; 17 | in_addr_t host = INADDR_ANY; 18 | in_port_t port = 179; 19 | bool verbose = false; 20 | }; 21 | 22 | class Feeder { 23 | public: 24 | Feeder(const FeederConfiguration &feder_config); 25 | bool start(); 26 | void stop(); 27 | void join(); 28 | 29 | private: 30 | void tick(); 31 | void handleAccept(); 32 | void handleSession(const char *peer_addr, int fd); 33 | 34 | int fd_sock; 35 | bool running; 36 | in_addr_t host; 37 | in_port_t port; 38 | 39 | libbgp::BgpLogHandler logger; 40 | libbgp::BgpLogHandler fsm_logger; 41 | libbgp::BgpConfig config_template; 42 | libbgp::BgpRib4 rib; 43 | libbgp::RouteEventBus bus; 44 | 45 | std::mutex list_mtx; 46 | std::vector fsms; 47 | std::vector threads; 48 | //std::vector client_fds; 49 | 50 | Fetcher fetcher; 51 | 52 | uint32_t update_interval; 53 | }; 54 | 55 | } 56 | 57 | #endif // FEEDER_H -------------------------------------------------------------------------------- /fetcher.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "fetcher.h" 4 | #include "math.h" 5 | #define DELEGATE_DB "http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest" 6 | 7 | namespace cnrf { 8 | 9 | static size_t do_write(void *ptr, size_t size, size_t nmemb, Fetcher *fetcher) { 10 | return fetcher->handleRead((char *) ptr, size * nmemb); 11 | } 12 | 13 | Fetcher::Fetcher(libbgp::BgpRib4 *rib, libbgp::RouteEventBus *rev_bus, uint32_t nexthop) { 14 | curl = curl_easy_init(); 15 | curl_easy_setopt(curl, CURLOPT_URL, DELEGATE_DB); 16 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, do_write); 17 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, this); 18 | curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 65535L); 19 | this->rib = rib; 20 | this->rev_bus = rev_bus; 21 | this->nexthop = nexthop; 22 | buffer_left = 0; 23 | } 24 | 25 | Fetcher::~Fetcher() { 26 | curl_easy_cleanup(curl); 27 | curl_global_cleanup(); 28 | } 29 | 30 | size_t Fetcher::handleRead(const char* buffer, size_t size) { 31 | size_t buf_sz = size; 32 | 33 | if (buffer_left != 0) { 34 | memcpy(read_buffer + buffer_left, buffer, size); 35 | buf_sz = size + buffer_left; 36 | } 37 | 38 | const char *cur = buffer_left != 0 ? read_buffer : buffer; 39 | const char *ptr = cur; 40 | size_t read = 0; 41 | 42 | while (read < buf_sz) { 43 | if (*ptr != '\n' || *ptr == 0) { 44 | ptr++; 45 | read++; 46 | continue; 47 | } 48 | 49 | if (*cur != '#') { 50 | size_t line_len = ptr - cur; 51 | if (line_len > 128) throw "invalid_line_len"; 52 | memcpy(line_buffer, cur, line_len); 53 | line_buffer[line_len] = 0; 54 | 55 | char *rest = line_buffer; 56 | 57 | (void) strtok_r(rest, "|", &rest); // skip first field 58 | char *cc = strtok_r(rest, "|", &rest); 59 | if (strncmp("CN", cc, 2) != 0) goto nextline; 60 | char *type = strtok_r(rest, "|", &rest); 61 | if (strncmp("ipv4", type, 4) != 0) goto nextline; 62 | char *prefix = strtok_r(rest, "|", &rest); 63 | uint8_t length = 32 - log(atoi(strtok_r(rest, "|", &rest)))/log(2); 64 | cur_allocs.push_back(libbgp::Prefix4(prefix, length)); 65 | 66 | size_t cur_sz = cur_allocs.size(); 67 | if (cur_sz % 1000 == 0 && cur_sz != 0) { 68 | logger.log(libbgp::INFO, "Fetcher::handleRead: updating: %zu delegations loaded.\n", cur_sz); 69 | } 70 | } 71 | 72 | nextline: 73 | cur = ptr + 1; 74 | ptr++; 75 | read++; 76 | } 77 | 78 | buffer_left = ptr - cur; 79 | 80 | if (buffer_left > 0) { 81 | memcpy(read_buffer, cur, buffer_left); 82 | read_buffer[buffer_left] = 0; 83 | } 84 | 85 | return size; 86 | } 87 | 88 | bool Fetcher::updateRib() { 89 | std::vector added; 90 | std::vector dropped; 91 | cur_allocs.clear(); 92 | long response_code; 93 | double elapsed; 94 | logger.log(libbgp::INFO, "Fetcher::updateRib: fetching latest delegations...\n"); 95 | curl_easy_perform(curl); 96 | curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); 97 | curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &elapsed); 98 | 99 | if (response_code != 200) { 100 | logger.log(libbgp::WARN, "Fetcher::updateRib: failed to fetch delegations: HTTP %ld.\n", response_code); 101 | return false; 102 | } 103 | 104 | 105 | logger.log(libbgp::INFO, "Fetcher::updateRib: %zu delegations fetched in %f seconds, computing diffs...\n", cur_allocs.size(), elapsed); 106 | 107 | for (const libbgp::Prefix4 &prefix : cur_allocs) { 108 | if (std::find(last_allocs.begin(), last_allocs.end(), prefix) == last_allocs.end()) { 109 | added.push_back(prefix); 110 | } 111 | } 112 | 113 | for (const libbgp::Prefix4 &prefix : last_allocs) { 114 | if (std::find(cur_allocs.begin(), cur_allocs.end(), prefix) == cur_allocs.end()) { 115 | dropped.push_back(prefix); 116 | } 117 | } 118 | 119 | logger.log(libbgp::INFO, "Fetcher::updateRib: %zu routes added, %zu routes dropped.\n", added.size(), dropped.size()); 120 | 121 | last_allocs = cur_allocs; 122 | std::vector added_e = rib->insert(&logger, added, nexthop); 123 | if (added_e.size() > 0) { 124 | std::vector> attrib = added_e[0].attribs; 125 | libbgp::Route4AddEvent ae; 126 | ae.shared_attribs = &attrib; 127 | ae.new_routes = &added; 128 | rev_bus->publish(NULL, ae); 129 | } 130 | 131 | std::vector dropped_e; 132 | for (const libbgp::Prefix4 &r : dropped) { 133 | std::pair rslt = rib->withdraw(0, r); 134 | if (!rslt.first) dropped_e.push_back(r); 135 | } 136 | 137 | if (dropped_e.size() > 0) { 138 | libbgp::Route4WithdrawEvent we; 139 | we.routes = &dropped_e; 140 | rev_bus->publish(NULL, we); 141 | } 142 | 143 | logger.log(libbgp::INFO, "Fetcher::updateRib: rib updated.\n"); 144 | 145 | return true; 146 | } 147 | 148 | } -------------------------------------------------------------------------------- /fetcher.h: -------------------------------------------------------------------------------- 1 | #ifndef FETCHER_H 2 | #define FETCHER_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace cnrf { 12 | 13 | class Fetcher { 14 | public: 15 | Fetcher(libbgp::BgpRib4 *rib, libbgp::RouteEventBus *rev_bus, uint32_t nexthop); 16 | ~Fetcher(); 17 | bool updateRib(); 18 | bool getRoutesDiff(std::vector &added, std::vector &dropped); 19 | size_t handleRead(const char* buffer, size_t size); 20 | 21 | private: 22 | char line_buffer[256]; 23 | char read_buffer[65536]; 24 | size_t buffer_left; 25 | uint32_t nexthop; 26 | 27 | std::vector last_allocs; 28 | std::vector cur_allocs; 29 | libbgp::BgpRib4 *rib; 30 | libbgp::RouteEventBus *rev_bus; 31 | libbgp::BgpLogHandler logger; 32 | 33 | CURL *curl; 34 | }; 35 | 36 | } 37 | 38 | #endif // FETCHER_H -------------------------------------------------------------------------------- /routefeed.cc: -------------------------------------------------------------------------------- 1 | #include "feeder.h" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace cnrf; 7 | 8 | static Feeder *feeder = nullptr; 9 | 10 | void handle_sig(__attribute__((unused)) int sig) { 11 | fprintf(stderr, "Got SIGINT/SIGTERM, stopping...\n"); 12 | if (feeder != nullptr) feeder->stop(); 13 | } 14 | 15 | void help() { 16 | fprintf(stderr, "usage: routefeed [-l HOST] [-p PORT] [-t INTERVAL] -a ASN -i BGP_ID -n NEXTHOP\n"); 17 | fprintf(stderr, " [-c CONFIG] [-v]\n"); 18 | fprintf(stderr, "\n"); 19 | fprintf(stderr, "cn-routefeed is a BGP speaker that feeds all China IPv4 delegations to peer. \n"); 20 | fprintf(stderr, "Delegation information is fetch from APNIC.\n"); 21 | fprintf(stderr, "\n"); 22 | fprintf(stderr, "required arguments:\n"); 23 | fprintf(stderr, " -a ASN Local ASN of the BGP speaker.\n"); 24 | fprintf(stderr, " -i BGP_ID BGP ID (Router ID) of the BGP speaker.\n"); 25 | fprintf(stderr, " -n NEXTHOP Nexthop to use when sending routes.\n"); 26 | fprintf(stderr, "\n"); 27 | fprintf(stderr, "optional arguments:\n"); 28 | fprintf(stderr, " -l HOST IP address to bind the BGP speaker on. (default: 0.0.0.0)\n"); 29 | fprintf(stderr, " -p PORT TCP port number to bind the BGP speaker on. (default: 179)\n"); 30 | fprintf(stderr, " -t INTERVAL Time in second to wait between fetching update from APNIC.\n"); 31 | fprintf(stderr, " (default: 86400)\n"); 32 | fprintf(stderr, " -c CONFIG Read command line arguments from file.\n"); 33 | fprintf(stderr, " -v Enable debug mode (verbose).\n"); 34 | } 35 | 36 | void free_argv(int argc, char **argv) { 37 | if (argv == NULL || argc == 0) return; 38 | for (int i = 0; i < argc; i++) { 39 | free(argv[i]); 40 | } 41 | 42 | free(argv); 43 | } 44 | 45 | int parse_config(int argc, char **argv, FeederConfiguration &config) { 46 | if (argv == NULL || argc == 0) return 0; 47 | 48 | for (int i = 0; i < argc; ++i) { 49 | if (i + 1 < argc && strncmp("-l", argv[i], 2) == 0 && strlen(argv[i]) == 2) { 50 | if (inet_pton(AF_INET, argv[++i], &config.host) != 1) { 51 | fprintf(stderr, "invalid host: \"%s\".\n", argv[i]); 52 | return 1; 53 | } 54 | } else if (i + 1 < argc && strncmp("-p", argv[i], 2) == 0 && strlen(argv[i]) == 2) { 55 | config.port = atoi(argv[++i]); 56 | } else if (i + 1 < argc && strncmp("-a", argv[i], 2) == 0 && strlen(argv[i]) == 2) { 57 | config.my_asn = atoi(argv[++i]); 58 | } else if (i + 1 < argc && strncmp("-i", argv[i], 2) == 0 && strlen(argv[i]) == 2) { 59 | if (inet_pton(AF_INET, argv[++i], &config.bgp_id) != 1) { 60 | fprintf(stderr, "invalid bgp_id: \"%s\".\n", argv[i]); 61 | return 1; 62 | } 63 | } else if (i + 1 < argc && strncmp("-n", argv[i], 2) == 0 && strlen(argv[i]) == 2) { 64 | if (inet_pton(AF_INET, argv[++i], &config.nexthop) != 1) { 65 | fprintf(stderr, "invalid nexthop: \"%s\".\n", argv[i]); 66 | return 1; 67 | } 68 | } else if (i + 1 < argc && strncmp("-t", argv[i], 2) == 0 && strlen(argv[i]) == 2) { 69 | config.update_interval = atoi(argv[++i]); 70 | } else if (i + 1 < argc && strncmp("-c", argv[i], 2) == 0 && strlen(argv[i]) == 2) { 71 | 72 | FILE *fp = fopen(argv[++i], "r"); 73 | if(!fp) { 74 | fprintf(stderr, "can't open config file: \"%s\".\n", argv[i]); 75 | return 1; 76 | } 77 | 78 | fseek(fp, 0L, SEEK_END); 79 | long sz = ftell(fp); 80 | rewind(fp); 81 | 82 | char buf[512]; 83 | memset(buf, 0, sizeof(buf)); 84 | 85 | char *buf_ptr = buf; 86 | if (sizeof(buf) < (size_t) sz) { 87 | fclose(fp); 88 | fprintf(stderr, "config file too big.\n"); 89 | return 1; 90 | } 91 | 92 | fread(buf, sz, 1, fp); 93 | fclose(fp); 94 | 95 | char **new_argv = NULL, *cur = NULL; 96 | int new_argc = 0; 97 | while ((cur = strsep(&buf_ptr, " \n\t")) != NULL) { 98 | if (new_argc == 0) { 99 | new_argv = (char **) malloc(sizeof(char *)); 100 | } else { 101 | new_argv = (char **) realloc(new_argv, (new_argc + 1) * sizeof(char *)); 102 | } 103 | 104 | new_argv[new_argc] = (char *) malloc(strlen(cur) + 1); 105 | strcpy(new_argv[new_argc], cur); 106 | ++new_argc; 107 | }; 108 | 109 | if (parse_config(new_argc, new_argv, config) == 1) { 110 | fprintf(stderr, "error parsing configuration.\n"); 111 | free_argv(new_argc, new_argv); 112 | return 1; 113 | } 114 | free_argv(new_argc, new_argv); 115 | 116 | } else if (strncmp("-v", argv[i], 2) == 0 && strlen(argv[i]) == 2) { 117 | config.verbose = true; 118 | } else { 119 | fprintf(stderr, "unknow command line argument: \"%s\".\n", argv[i]); 120 | return 1; 121 | } 122 | } 123 | 124 | return 0; 125 | } 126 | 127 | int main (int argc, char **argv) { 128 | FeederConfiguration config; 129 | 130 | if (parse_config(argc - 1, argv + 1, config) == 1) { 131 | help(); 132 | return 1; 133 | } 134 | 135 | if (config.my_asn == 0 || config.nexthop == 0 || config.bgp_id == 0) { 136 | help(); 137 | return 1; 138 | } 139 | 140 | signal(SIGINT, handle_sig); 141 | signal(SIGTERM, handle_sig); 142 | 143 | Feeder feeder(config); 144 | ::feeder = &feeder; 145 | 146 | feeder.start(); 147 | feeder.join(); 148 | 149 | return 0; 150 | } --------------------------------------------------------------------------------