aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2010-03-11 14:42:59 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2010-03-11 14:42:59 +0000
commitfd1d4a5da876516412ec51c4eb37333caa57a2bc (patch)
treec2d67a77bce73a35434ea337ecad5b94113210a1
parentb1f240b9e0b2c8771bc4ea910df218e616bb7118 (diff)
downloadpingu-fd1d4a5da876516412ec51c4eb37333caa57a2bc.tar.bz2
pingu-fd1d4a5da876516412ec51c4eb37333caa57a2bc.tar.xz
pingu: support for setting source-ip
This is needed so ip source routing works with shorewall The problem is that when we change the default gw, removing a gateway that went down, we are not able to ping remote host via that interface ...unless we set the source ip and have an ip route table with source ip. Shorewall sets that up.
-rw-r--r--pingu.c42
-rw-r--r--pingu.conf11
2 files changed, 34 insertions, 19 deletions
diff --git a/pingu.c b/pingu.c
index 2047901..1176aaf 100644
--- a/pingu.c
+++ b/pingu.c
@@ -39,7 +39,8 @@ char *default_down_action = NULL;
char *default_route_script = NULL;
struct provider {
- struct sockaddr_in address;
+ struct sockaddr_in dest_addr;
+ struct sockaddr_in src_addr;
char *name;
char *interface;
char *gateway;
@@ -128,7 +129,7 @@ int read_config(const char *file, struct provider_list *head)
if (strcmp(key, "host") == 0) {
p = xmalloc(sizeof(struct provider));
memset(p, 0, sizeof(struct provider));
- if (init_sockaddr(&p->address, value) < 0)
+ if (init_sockaddr(&p->dest_addr, value) < 0)
return 1;
p->gateway = xstrdup(value);
p->status = 1; /* online by default */
@@ -175,6 +176,9 @@ int read_config(const char *file, struct provider_list *head)
p->required_replies = atoi(value);
} else if (strcmp(key, "timeout") == 0) {
p->timeout = atof(value);
+ } else if (strcmp(key, "source-ip") == 0) {
+ if (init_sockaddr(&p->src_addr, value) < 0)
+ return 1;
} else {
log_error("Unknown keyword '%s' on line %i", key,
lineno);
@@ -184,8 +188,7 @@ int read_config(const char *file, struct provider_list *head)
}
/* returns true if it get at least required_replies/retries replies */
-int ping_status(struct sockaddr_in *to, int *seq, int retries,
- int required_replies, float timeout, const char *iface)
+int ping_status(struct provider *p, int *seq)
{
__u8 buf[1500];
struct iphdr *ip = (struct iphdr *) buf;
@@ -194,15 +197,24 @@ int ping_status(struct sockaddr_in *to, int *seq, int retries,
int retry;
int replies = 0;
int len = sizeof(struct iphdr) + sizeof(struct icmphdr);
- int fd = icmp_open(timeout);
-
- if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, iface,
- (iface == NULL) ? 0 : strlen(iface)+1) == -1)
+ int fd = icmp_open(p->timeout);
+
+ /* bidn to interface if set */
+ if (p->interface != NULL)
+ if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, p->interface,
+ strlen(p->interface)+1) == -1)
+ goto close_fd;
+
+ /* set source address */
+ if (bind(fd, (struct sockaddr *)&p->src_addr, sizeof(p->src_addr)) < 0){
+ log_error("bind source address %s: %s",
+ inet_ntoa(p->src_addr.sin_addr), strerror(errno));
goto close_fd;
+ }
- for (retry = 0; retry < retries && replies < required_replies; retry++) {
- icmp_send_ping(fd, (struct sockaddr *) to, sizeof(*to),
- *seq, len);
+ for (retry = 0; retry < p->retry && replies < p->required_replies; retry++) {
+ icmp_send_ping(fd, (struct sockaddr *)&p->dest_addr,
+ sizeof(p->dest_addr), *seq, len);
(*seq)++;
(*seq) &= 0xffff;
if ((len = icmp_read_reply(fd, (struct sockaddr *) &from,
@@ -220,7 +232,7 @@ close_fd:
printf("address=%s, replies=%i, required=%i\n",
inet_ntoa(to->sin_addr), replies, required_replies);
#endif
- return (replies >= required_replies);
+ return (replies >= p->required_replies);
}
static void print_version(const char *program)
@@ -264,7 +276,7 @@ char *get_provider_gateway(struct provider *p)
{
if (p->gateway != NULL)
return p->gateway;
- return inet_ntoa(p->address.sin_addr);
+ return inet_ntoa(p->dest_addr.sin_addr);
}
void exec_route_change(struct provider_list *head)
@@ -316,9 +328,7 @@ void ping_loop(struct provider_list *head, int interval)
change = 0;
SLIST_FOREACH(p, head, provider_list) {
int status;
- status = ping_status(&p->address, &seq, p->retry,
- p->required_replies, p->timeout,
- p->interface);
+ status = ping_status(p, &seq);
if (status != p->status) {
change++;
p->status = status;
diff --git a/pingu.conf b/pingu.conf
index 271e994..55f7ee2 100644
--- a/pingu.conf
+++ b/pingu.conf
@@ -2,24 +2,29 @@
# comments are prefixed with #
# global option
-interval 1
+interval 10
retry 3
timeout 1.0
# route-script will be executed every time anything changes status.
# All gateways that are "up" are sent as parameter.
route-script /etc/pingu/route-script
-host 10.65.67.11
+# host to ping
+host 10.65.67.1
name ISP-1
+# bind to interface
interface eth1
+# set the source ip
+source-ip 10.65.67.12
timeout 0.3
retry 2
up-action echo "isp 1 went up"
down-action echo "iso 1 went down"
-#host 10.2.0.3
+#host 10.2.0.1
#name ISP-2
#interface eth0
+#source-ip 10.2.0.3
#up-action /etc/pingu/isp2 up
#down-action /etc/pingu/isp2 down