Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -std=gnu99")

include_directories(.)
if(UNIX)
if(APPLE)
find_package(Argp)
if(ARGP_FOUND)
message(STATUS "argp found.")
Expand All @@ -15,7 +15,7 @@ if(UNIX)
else()
set(ARGP_INCLUDE_DIRS "")
set(ARGP_LIBRARIES "")
endif(UNIX)
endif(APPLE)

if(NOT RTRLIB_INCLUDE AND NOT RTRLIB_LIBRARY)
find_package(Rtr)
Expand Down
130 changes: 117 additions & 13 deletions bird-rtrlib-cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
#include <string.h>
#include <syslog.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "bird.h"
#include "cli.h"
Expand All @@ -47,13 +50,45 @@ static size_t bird_command_length = -1;
static char *bird_add_roa_table_arg = "";
// Main configuration.
static struct config config;
// for daemon loop
static int time_to_die = 0;
// fopr pidfile
static int pid_fd = -1;

/**
* Handle SIGPIPE on bird_socket, write error log entry
*/
void sigpipe_handler(int signum)
{
syslog(LOG_ERR, "Caught SIGPIPE %d.", signum);
if (config.quiet != true)
syslog(LOG_ERR, "Caught SIGPIPE %d.", signum);
}

void sigkill_handler(int signum)
{
syslog(LOG_INFO, "Got kill signal, cleaning up and exiting.");
/* Unlock and close lockfile */
if (pid_fd != -1) {
lockf(pid_fd, F_ULOCK, 0);
close(pid_fd);
}
/* Try to delete lockfile */
if (config.pidfile != NULL) {
unlink(config.pidfile);
}
time_to_die++;
}

void create_pidfile()
{
char str[256];
pid_fd = open(config.pidfile, O_RDWR|O_CREAT, 0640);
if (pid_fd < 0)
exit(EXIT_FAILURE);
if (lockf(pid_fd, F_TLOCK, 0) < 0)
exit(EXIT_FAILURE);
sprintf(str,"%d\n", getpid());
write(pid_fd, str, strlen(str));
}

/**
Expand Down Expand Up @@ -150,6 +185,18 @@ static void pfx_update_callback(struct pfx_table *table,
static char bird_response[BIRD_RSP_SIZE];
// Fetch IP address as string.
lrtr_ip_addr_to_str(&(record.prefix), ip_addr_str, sizeof(ip_addr_str));
// Crude way of filtering out sending Bird the wrong kind of updates
if (config.ip_version)
{
int prefix_allowed = 0;
// Is this an IPv4 prefix?
if ((strchr(ip_addr_str,'.') != NULL) && (strchr(config.ip_version, '4') != NULL) )
prefix_allowed++;
if ((strchr(ip_addr_str,':') != NULL) && (strchr(config.ip_version, '6') != NULL) )
prefix_allowed++;
if (prefix_allowed == 0)
return;
}
// Write BIRD command to buffer.
if (
snprintf(
Expand All @@ -169,11 +216,13 @@ static void pfx_update_callback(struct pfx_table *table,
return;
}
// Log the BIRD command and send it to the BIRD server.
syslog(LOG_INFO, "To BIRD: %s", bird_command);
if (config.quiet != true)
syslog(LOG_INFO, "To BIRD: %s", bird_command);
// reconnect bird_socket on SIGPIPE error, and resend BIRD command
while ((write(bird_socket, bird_command, strlen(bird_command)) < 0) &&
(errno == EPIPE)) {
syslog(LOG_ERR, "BIRD socket send failed, try reconnect!");
if (config.quiet != true)
syslog(LOG_ERR, "BIRD socket send failed, try reconnect!");
close(bird_socket);
bird_socket = bird_connect(config.bird_socket_path);
}
Expand All @@ -188,7 +237,13 @@ static void pfx_update_callback(struct pfx_table *table,
// log answer, if any valid response
if (size > 0) {
bird_response[size] = 0;
syslog(LOG_INFO, "From BIRD: %s", bird_response);
// Any bird response that doesn't start with 0000 is bad
if ((strstr(bird_response, "0000") == NULL) && (strstr(bird_response, "0001") == NULL))
syslog(LOG_ERR,"Bird command %s resulted in: %s\n", bird_command, bird_response);
// else
// fprintf (stdout,"%s %s/%d \t", added ? "add" : "del", ip_addr_str, record.min_len);
if (config.quiet != true)
syslog(LOG_INFO, "From BIRD: %s", bird_response);
}
}

Expand All @@ -200,6 +255,7 @@ static void pfx_update_callback(struct pfx_table *table,
*/
int main(int argc, char *argv[])
{

// Buffer for commands and its length.
char *command = 0;
size_t command_len = 0;
Expand All @@ -219,6 +275,33 @@ int main(int argc, char *argv[])
fprintf(stderr, "Invalid configuration parameters!\n");
return EXIT_FAILURE;
}
pid_t process_id = 0;
pid_t sid = 0;

// Launch daemon if configured
if (config.daemon == true)
{
process_id = fork ();
// fork failed
if (process_id < 0)
{
fprintf(stderr,"fork failed!\n");
exit(1);
}
// Parent process, end it
if (process_id > 0)
exit(0);

// We're now in the child process
if (config.pidfile != NULL)
create_pidfile();
syslog(LOG_INFO, "initiated and running.");
sid = setsid();
if (sid < 0)
exit(1);
chdir ("/");
}

// Setup BIRD ROA table command argument.
if (config.bird_roa_table) {
init_bird_add_roa_table_arg(config.bird_roa_table);
Expand All @@ -229,7 +312,7 @@ int main(int argc, char *argv[])
bird_socket = bird_connect(config.bird_socket_path);
if (bird_socket == -1) {
cleanup();
fprintf(stderr, "Failed to connect to BIRD socket!\n");
syslog(LOG_ERR, "Failed to connect to BIRD socket!\n");
return EXIT_FAILURE;
}

Expand All @@ -252,7 +335,7 @@ int main(int argc, char *argv[])
break;
default:
cleanup();
fprintf(stderr, "Invalid connection type, use tcp or ssh!\n");
syslog(LOG_ERR, "Invalid connection type, use tcp or ssh!\n");
return EXIT_FAILURE;
}

Expand All @@ -270,26 +353,47 @@ int main(int argc, char *argv[])
pfx_update_callback, NULL, NULL, NULL);
// check for init errors
if (ret == RTR_ERROR) {
fprintf(stderr, "Error in rtr_mgr_init!\n");
syslog(LOG_ERR, "Error in rtr_mgr_init!\n");
return EXIT_FAILURE;
}
else if (ret == RTR_INVALID_PARAM) {
fprintf(stderr, "Invalid params passed to rtr_mgr_init\n");
syslog(LOG_ERR, "Invalid params passed to rtr_mgr_init\n");
return EXIT_FAILURE;
}
// check if rtr_mgr config valid
if (!conf) {
fprintf(stderr, "No config for rtr manager!\n");
syslog(LOG_ERR, "No config for rtr manager!\n");
return EXIT_FAILURE;
}
// set handler for SIGPIPE
signal(SIGPIPE, sigpipe_handler);
// set handler for SIGKILL and SIGTERM
signal(SIGKILL, sigkill_handler);
signal(SIGTERM, sigkill_handler);
// start rtr_mgr
rtr_mgr_start(conf);
// Server loop. Read commands from stdin.
while (getline(&command, &command_len, stdin) != -1) {
if (strncmp(command, CMD_EXIT, strlen(CMD_EXIT)) == 0)
break;

if (config.daemon == true)
{
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// Child loop
while(time_to_die == 0)
sleep(1);
}
else
{
fprintf(stdout, "bird-rtrlib-cli connected to %s:%s ready for IP versions %s.\nType 'exit' to clean up and quit.\n",
config.rtr_host,
config.rtr_port,
config.ip_version ? config.ip_version : "all"
);
// CLI loop. Read commands from stdin.
while (getline(&command, &command_len, stdin) != -1) {
if (strncmp(command, CMD_EXIT, strlen(CMD_EXIT)) == 0)
break;
}
}
// Clean up RTRLIB memory.
rtr_mgr_stop(conf);
Expand Down
48 changes: 48 additions & 0 deletions cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
#define ARGKEY_RTRSSH_HOSTKEY 0x101
#define ARGKEY_RTRSSH_PRIVKEY 0x102
#define ARGKEY_RTRSSH_USERNAME 0x103
#define ARGKEY_IP_VERSION 'v'
#define ARGKEY_QUIET 'q'
#define ARGKEY_DAEMON 'd'
#define ARGKEY_PIDFILE 'p'

// Parser function for argp_parse().
static error_t argp_parser(int key, char *arg, struct argp_state *state)
Expand Down Expand Up @@ -67,6 +71,18 @@ static error_t argp_parser(int key, char *arg, struct argp_state *state)
case ARGKEY_RTRSSH_USERNAME:
config->rtr_ssh_username = arg;
break;
case ARGKEY_IP_VERSION:
config->ip_version = arg;
break;
case ARGKEY_QUIET:
config->quiet = true;
break;
case ARGKEY_DAEMON:
config->daemon = true;
break;
case ARGKEY_PIDFILE:
config->pidfile = arg;
break;
default:
// Process unknown argument.
return ARGP_ERR_UNKNOWN;
Expand Down Expand Up @@ -148,6 +164,38 @@ int parse_cli(int argc, char **argv, struct config *config)
"used. Uses the user's default identity file if not specified.",
2
},
{
"version",
ARGKEY_IP_VERSION,
"<4|6>",
0,
"(Optional) Indicate if the bird daemon wants IPv4 or IPv6 only updates.",
2
},
{
"quiet",
ARGKEY_QUIET,
0,
0,
"(Optional) Report only errors.",
1
},
{
"daemon",
ARGKEY_DAEMON,
0,
0,
"(Optional) run as daemon, detach from terminal.",
1
},
{
"pidfile",
ARGKEY_PIDFILE,
"<PIDFILE>",
0,
"(Optional) Name of the pidfile",
2
},
{0}
};
// argp structure to be passed to argp_parse().
Expand Down
6 changes: 6 additions & 0 deletions config.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ enum connection_type {
ssh // SSH connection
};

typedef enum { false, true } bool;

/**
* Application configuration structure.
*/
Expand All @@ -41,6 +43,10 @@ struct config {
char *rtr_ssh_username;
char *rtr_ssh_hostkey_file;
char *rtr_ssh_privkey_file;
char *ip_version;
bool quiet;
bool daemon;
char *pidfile;
};

/**
Expand Down