aboutsummaryrefslogtreecommitdiffstats
path: root/pingu.c
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 /pingu.c
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.
Diffstat (limited to 'pingu.c')
-rw-r--r--pingu.c42
1 files changed, 26 insertions, 16 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;