aboutsummaryrefslogtreecommitdiffstats
path: root/pingu.c
diff options
context:
space:
mode:
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;