irwand
June 12th, 2008, 12:30 AM
I recently made a patch to ez-ipupdate so that it will run a program to determine the IP of the server machine. Normally ez-ipupdate gets the machine's IP automatically but only using the local IP of the machine. This doesn't quite work for me since my computer is located behind a NAT router.
Unfortunately, I can't find anyway to contact the maintainer of ez-ipupdate. The email address of the maintainer is no longer valid. I'm hoping that by posting this patch here, other people might find this useful. If you know the current maintainer of ez-ipupdate, please let me know so I can send this patch his/her way.
Here's the patch:
diff -aur ez-ipupdate-3.0.11b7/ez-ipupdate.c ez-ipupdate-3.0.11b7+ipcommand/ez-ipupdate.c
--- ez-ipupdate-3.0.11b7/ez-ipupdate.c 2002-03-11 17:31:47.000000000 -0600
+++ ez-ipupdate-3.0.11b7+ipcommand/ez-ipupdate.c 2008-01-03 00:43:22.000000000 -0600
@@ -265,6 +265,7 @@
int max_interval = 0;
int service_set = 0;
char *post_update_cmd = NULL;
+char *get_ip_cmd = NULL;
char *post_update_cmd_arg = NULL;
int connection_type = 1;
time_t last_update = 0;
@@ -547,6 +548,7 @@
CMD_debug,
CMD_execute,
CMD_foreground,
+ CMD_getipcmd,
CMD_quiet,
CMD_timeout,
CMD_run_as_user,
@@ -572,6 +574,7 @@
{ CMD_pid_file, "pid-file", CONF_NEED_ARG, 1, conf_handler, "%s=<file>" },
{ CMD_host, "host", CONF_NEED_ARG, 1, conf_handler, "%s=<host>" },
{ CMD_interface, "interface", CONF_NEED_ARG, 1, conf_handler, "%s=<interface>" },
+ { CMD_getipcmd, "getipcmd", CONF_NEED_ARG, 1, conf_handler, "%s=<shell command>" },
{ CMD_mx, "mx", CONF_NEED_ARG, 1, conf_handler, "%s=<mail exchanger>" },
{ CMD_max_interval, "max-interval", CONF_NEED_ARG, 1, conf_handler, "%s=<number of seconds between updates>" },
{ CMD_notify_email, "notify-email", CONF_NEED_ARG, 1, conf_handler, "%s=<address to email if bad things happen>" },
@@ -630,6 +633,7 @@
fprintf(stdout, " -g, --request-uri <uri>\tURI to send updates to\n");
fprintf(stdout, " -h, --host <host>\t\tstring to send as host parameter\n");
fprintf(stdout, " -i, --interface <iface>\twhich interface to use\n");
+ fprintf(stdout, " -j, --getipcmd <command>\tshell command to print a line IP address to use. This override interface option.\n");
fprintf(stdout, " -L, --cloak_title <host>\tsome stupid thing for DHS only\n");
fprintf(stdout, " -m, --mx <mail exchange>\tstring to send as your mail exchange\n");
fprintf(stdout, " -M, --max-interval <# of sec>\tmax time in between updates\n");
@@ -926,6 +930,19 @@
dprintf((stderr, "fork()ing off\n"));
break;
+ case CMD_getipcmd:
+#if defined(HAVE_WAITPID) || defined(HAVE_WAIT)
+ if(get_ip_cmd) { free(get_ip_cmd); }
+ get_ip_cmd = malloc(strlen(optarg) + 1 + ARGLENGTH + 1);
+ post_update_cmd_arg = get_ip_cmd + strlen(optarg) + 1;
+ sprintf(get_ip_cmd, "%s ", optarg);
+ dprintf((stderr, "get_ip_cmd: %s\n", get_ip_cmd));
+#else
+ fprintf(stderr, "command execution not enabled at compile time\n");
+ exit(1);
+#endif
+ break;
+
case CMD_pid_file:
#if HAVE_GETPID
if(pid_file) { free(pid_file); }
@@ -1177,6 +1194,7 @@
{"pid-file", required_argument, 0, 'F'},
{"host", required_argument, 0, 'h'},
{"interface", required_argument, 0, 'i'},
+ {"getipcmd", required_argument, 0, 'j'},
{"cloak_title", required_argument, 0, 'L'},
{"mx", required_argument, 0, 'm'},
{"max-interval", required_argument, 0, 'M'},
@@ -1205,7 +1223,7 @@
#endif
int opt;
- while((opt=xgetopt(argc, argv, "a:b:c:dDe:fF:g:h:i:L:m:M:N:o:p:P:qQ:r:R:s:S:t:T:U: u:wHVCZz:",
+ while((opt=xgetopt(argc, argv, "a:b:c:dDe:fF:g:h:i:j:L:m:M:N:o:p:P:qQ:r:R:s:S:t:T: U:u:wHVCZz:",
long_options, NULL)) != -1)
{
switch (opt)
@@ -1264,6 +1282,10 @@
option_handler(CMD_interface, optarg);
break;
+ case 'j':
+ option_handler(CMD_getipcmd, optarg);
+ break;
+
case 'L':
option_handler(CMD_cloak_title, optarg);
break;
@@ -1602,8 +1624,17 @@
return(bread);
}
+char* get_ip_from_cmd(char *cmd, int* error);
int get_if_addr(int sock, char *name, struct sockaddr_in *sin)
{
+ if (strcmp(name, "getipcmd") == 0)
+ {
+ int error;
+ char *ipstr = get_ip_from_cmd(get_ip_cmd, &error);
+ inet_aton(ipstr, &(sin->sin_addr));
+ return error;
+ }
+
#ifdef IF_LOOKUP
struct ifreq ifr;
@@ -4341,6 +4372,110 @@
#endif
}
+char* get_ip_from_cmd(char *cmd, int* error)
+{
+ static char newipbuf[64];
+ newipbuf[0]='\0';
+ *error = 0;
+ char *retVal, *tail;
+#if (defined(HAVE_WAITPID) || defined(HAVE_WAIT)) && (defined(HAVE_VFORK) || defined(HAVE_FORK))
+ int kid;
+ int exit_code;
+ int ip_pipe[2];
+
+ pipe(ip_pipe);
+
+ /*
+ if(res == -1)
+ {
+ show_message("(%s) error running post update command: %s\n",
+ N_STR(host), error_string);
+ }
+ else
+ {
+ show_message(
+ "(%s) error running post update command, command exit code: %d\n",
+ N_STR(host), res);
+ }
+ */
+
+ switch((kid=vfork()))
+ {
+ case -1:
+ if(!(options & OPT_QUIET))
+ {
+ perror("fork");
+ }
+ show_message("(%s) error running get_ip_cmd: %s\n",
+ N_STR(host), error_string);
+ *error = -1;
+ return(newipbuf);
+ break;
+ case 0:
+ /* child */
+ close(ip_pipe[0]);
+ close(1);
+ dup2(ip_pipe[1],1);
+ execl("/bin/sh", "sh", "-c", cmd, (char *)0);
+ if(!(options & OPT_QUIET))
+ {
+ perror("exec");
+ }
+ exit(1);
+ break;
+ default:
+ /* parent */
+ dprintf((stderr, "forked kid: %d\n", kid));
+ break;
+ }
+
+# ifdef HAVE_WAITPID
+ if(waitpid(kid, &exit_code, 0) != kid)
+ {
+ dprintf((stderr, "forked kid: %d\n", kid));
+ close(ip_pipe[0]);
+ close(ip_pipe[1]);
+ *error = -1;
+ return(newipbuf);
+ }
+# else
+ if(wait(&exit_code) != kid)
+ {
+ close(ip_pipe[0]);
+ close(ip_pipe[1]);
+ *error = -1;
+ return(newipbuf);
+ }
+# endif
+ exit_code = WEXITSTATUS(exit_code);
+ *error = exit_code;
+
+ read(ip_pipe[0], newipbuf, 64);
+ close(ip_pipe[0]);
+ close(ip_pipe[1]);
+
+ /* cleanup return value string, find the beginning of IP address */
+ newipbuf[63] = '\0'; /* set end condition, just in case */
+ for (retVal = newipbuf; *retVal && (*retVal < '0' || *retVal > '9'); ++retVal) {}
+ /* cleanup return value string, cleanup trailing white space */
+ for (tail = retVal; *tail && ((*tail >= '0' && *tail <= '9') || *tail == '.'); ++tail) {}
+ *tail = '\0';
+
+ if (!is_dotted_quad(retVal))
+ retVal[0]='\0';
+
+ dprintf((stderr, "get_ip_from_cmd, got ip: %s\n", retVal));
+ if (*error != 0)
+ {
+ show_message( "ez-ipupdate: get_ip_from_cmd, got ip: %s, error: %d\n", retVal, *error);
+ }
+
+ return(retVal);
+#else
+ return(-1);
+#endif
+}
+
void handle_sig(int sig)
{
@@ -4395,7 +4530,7 @@
mcheck(NULL);
#endif
- dprintf((stderr, "staring...\n"));
+ dprintf((stderr, "starting...\n"));
program_name = argv[0];
options = 0;
@@ -4473,6 +4608,12 @@
request = strdup(request_over_ride == NULL ? service->default_request : request_over_ride);
dprintf((stderr, "request: %s\n", request));
+ if (get_ip_cmd)
+ {
+ if (interface) free(interface);
+ interface = strdup("getipcmd");
+ }
+
if(service->init != NULL)
{
service->init();
@@ -4512,9 +4653,12 @@
if(!(options & OPT_FOREGROUND))
{
# if HAVE_SYSLOG_H
+ /* If we close these, get_ip_from_cmd() doesn't behave correctly,
+ * because new files opened acts as stdin, stdout, and stderr, screwing
+ * things up.
close(0);
close(1);
- close(2);
+ close(2); */
# endif
if(fork() > 0) { exit(0); } /* parent */
}
Here is what the configuration file looks like:
#!/usr/sbin/ez-ipupdate -c
###
### Default ez-ipupdate configuration file - EDIT WITH CARE
### Use `dpkg-reconfigure ez-ipupdate' to update the debconf-generated lines.
###
### The following lines were generated by debconf
service-type=<your-service-type>
#server=(default)
user=<your-user-and-password>
host=<your-host>
#interface=eth0
#wildcard
#mx=(none)
run-as-user=ez-ipupd
cache-file=/var/cache/ez-ipupdate/default-cache
daemon
### Changes below this line will be preserved on upgrades.
getipcmd=/usr/local/bin/whatsmyip.pl
period=7200
The configuration tells ez-ipupdate to execute whatsmyip.pl to get the IP address. This executable must just print out the IP address of the machine on stdout using any method that works for your situation. I suggest if at all possible to not use web-scraping. Instead, try to contact your router and get your real IP address from there. Unfortunately for my situation, my router isn't straightforward, so I resort to web-scraping. The code I use for whatsmyip.pl is as follows:
#!/usr/bin/perl -wT
use strict;
use LWP::Simple;
my @checkIPURLs = (
"http://www.ipchicken.com",
"http://checkip.dyndns.com",
"http://ipdetect.dnspark.com",
"http://www.whatismyip.org",
"http://ipswift.com",
"http://www.cmyip.com"
);
my $range = scalar(@checkIPURLs);
my $maxLoop = 10;
my $random_number;
my $url;
my $response;
my $gotit;
do {
$gotit = 0;
$random_number = int(rand($range));
$url = $checkIPURLs[$random_number];
$response = get($url);
$response =~ s/<.*?>//gs;
$response =~ s/.*?([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/$1/gs;
$maxLoop--;
$gotit = 1 if ($response =~ m/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/);
} while (!$gotit && $maxLoop > 0);
if ($response =~ m/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/)
{
print "$response\n";
exit 0;
}
else
{
print "\n";
exit 1;
}
That's it. I hope that can help someone.
Thanks
Unfortunately, I can't find anyway to contact the maintainer of ez-ipupdate. The email address of the maintainer is no longer valid. I'm hoping that by posting this patch here, other people might find this useful. If you know the current maintainer of ez-ipupdate, please let me know so I can send this patch his/her way.
Here's the patch:
diff -aur ez-ipupdate-3.0.11b7/ez-ipupdate.c ez-ipupdate-3.0.11b7+ipcommand/ez-ipupdate.c
--- ez-ipupdate-3.0.11b7/ez-ipupdate.c 2002-03-11 17:31:47.000000000 -0600
+++ ez-ipupdate-3.0.11b7+ipcommand/ez-ipupdate.c 2008-01-03 00:43:22.000000000 -0600
@@ -265,6 +265,7 @@
int max_interval = 0;
int service_set = 0;
char *post_update_cmd = NULL;
+char *get_ip_cmd = NULL;
char *post_update_cmd_arg = NULL;
int connection_type = 1;
time_t last_update = 0;
@@ -547,6 +548,7 @@
CMD_debug,
CMD_execute,
CMD_foreground,
+ CMD_getipcmd,
CMD_quiet,
CMD_timeout,
CMD_run_as_user,
@@ -572,6 +574,7 @@
{ CMD_pid_file, "pid-file", CONF_NEED_ARG, 1, conf_handler, "%s=<file>" },
{ CMD_host, "host", CONF_NEED_ARG, 1, conf_handler, "%s=<host>" },
{ CMD_interface, "interface", CONF_NEED_ARG, 1, conf_handler, "%s=<interface>" },
+ { CMD_getipcmd, "getipcmd", CONF_NEED_ARG, 1, conf_handler, "%s=<shell command>" },
{ CMD_mx, "mx", CONF_NEED_ARG, 1, conf_handler, "%s=<mail exchanger>" },
{ CMD_max_interval, "max-interval", CONF_NEED_ARG, 1, conf_handler, "%s=<number of seconds between updates>" },
{ CMD_notify_email, "notify-email", CONF_NEED_ARG, 1, conf_handler, "%s=<address to email if bad things happen>" },
@@ -630,6 +633,7 @@
fprintf(stdout, " -g, --request-uri <uri>\tURI to send updates to\n");
fprintf(stdout, " -h, --host <host>\t\tstring to send as host parameter\n");
fprintf(stdout, " -i, --interface <iface>\twhich interface to use\n");
+ fprintf(stdout, " -j, --getipcmd <command>\tshell command to print a line IP address to use. This override interface option.\n");
fprintf(stdout, " -L, --cloak_title <host>\tsome stupid thing for DHS only\n");
fprintf(stdout, " -m, --mx <mail exchange>\tstring to send as your mail exchange\n");
fprintf(stdout, " -M, --max-interval <# of sec>\tmax time in between updates\n");
@@ -926,6 +930,19 @@
dprintf((stderr, "fork()ing off\n"));
break;
+ case CMD_getipcmd:
+#if defined(HAVE_WAITPID) || defined(HAVE_WAIT)
+ if(get_ip_cmd) { free(get_ip_cmd); }
+ get_ip_cmd = malloc(strlen(optarg) + 1 + ARGLENGTH + 1);
+ post_update_cmd_arg = get_ip_cmd + strlen(optarg) + 1;
+ sprintf(get_ip_cmd, "%s ", optarg);
+ dprintf((stderr, "get_ip_cmd: %s\n", get_ip_cmd));
+#else
+ fprintf(stderr, "command execution not enabled at compile time\n");
+ exit(1);
+#endif
+ break;
+
case CMD_pid_file:
#if HAVE_GETPID
if(pid_file) { free(pid_file); }
@@ -1177,6 +1194,7 @@
{"pid-file", required_argument, 0, 'F'},
{"host", required_argument, 0, 'h'},
{"interface", required_argument, 0, 'i'},
+ {"getipcmd", required_argument, 0, 'j'},
{"cloak_title", required_argument, 0, 'L'},
{"mx", required_argument, 0, 'm'},
{"max-interval", required_argument, 0, 'M'},
@@ -1205,7 +1223,7 @@
#endif
int opt;
- while((opt=xgetopt(argc, argv, "a:b:c:dDe:fF:g:h:i:L:m:M:N:o:p:P:qQ:r:R:s:S:t:T:U: u:wHVCZz:",
+ while((opt=xgetopt(argc, argv, "a:b:c:dDe:fF:g:h:i:j:L:m:M:N:o:p:P:qQ:r:R:s:S:t:T: U:u:wHVCZz:",
long_options, NULL)) != -1)
{
switch (opt)
@@ -1264,6 +1282,10 @@
option_handler(CMD_interface, optarg);
break;
+ case 'j':
+ option_handler(CMD_getipcmd, optarg);
+ break;
+
case 'L':
option_handler(CMD_cloak_title, optarg);
break;
@@ -1602,8 +1624,17 @@
return(bread);
}
+char* get_ip_from_cmd(char *cmd, int* error);
int get_if_addr(int sock, char *name, struct sockaddr_in *sin)
{
+ if (strcmp(name, "getipcmd") == 0)
+ {
+ int error;
+ char *ipstr = get_ip_from_cmd(get_ip_cmd, &error);
+ inet_aton(ipstr, &(sin->sin_addr));
+ return error;
+ }
+
#ifdef IF_LOOKUP
struct ifreq ifr;
@@ -4341,6 +4372,110 @@
#endif
}
+char* get_ip_from_cmd(char *cmd, int* error)
+{
+ static char newipbuf[64];
+ newipbuf[0]='\0';
+ *error = 0;
+ char *retVal, *tail;
+#if (defined(HAVE_WAITPID) || defined(HAVE_WAIT)) && (defined(HAVE_VFORK) || defined(HAVE_FORK))
+ int kid;
+ int exit_code;
+ int ip_pipe[2];
+
+ pipe(ip_pipe);
+
+ /*
+ if(res == -1)
+ {
+ show_message("(%s) error running post update command: %s\n",
+ N_STR(host), error_string);
+ }
+ else
+ {
+ show_message(
+ "(%s) error running post update command, command exit code: %d\n",
+ N_STR(host), res);
+ }
+ */
+
+ switch((kid=vfork()))
+ {
+ case -1:
+ if(!(options & OPT_QUIET))
+ {
+ perror("fork");
+ }
+ show_message("(%s) error running get_ip_cmd: %s\n",
+ N_STR(host), error_string);
+ *error = -1;
+ return(newipbuf);
+ break;
+ case 0:
+ /* child */
+ close(ip_pipe[0]);
+ close(1);
+ dup2(ip_pipe[1],1);
+ execl("/bin/sh", "sh", "-c", cmd, (char *)0);
+ if(!(options & OPT_QUIET))
+ {
+ perror("exec");
+ }
+ exit(1);
+ break;
+ default:
+ /* parent */
+ dprintf((stderr, "forked kid: %d\n", kid));
+ break;
+ }
+
+# ifdef HAVE_WAITPID
+ if(waitpid(kid, &exit_code, 0) != kid)
+ {
+ dprintf((stderr, "forked kid: %d\n", kid));
+ close(ip_pipe[0]);
+ close(ip_pipe[1]);
+ *error = -1;
+ return(newipbuf);
+ }
+# else
+ if(wait(&exit_code) != kid)
+ {
+ close(ip_pipe[0]);
+ close(ip_pipe[1]);
+ *error = -1;
+ return(newipbuf);
+ }
+# endif
+ exit_code = WEXITSTATUS(exit_code);
+ *error = exit_code;
+
+ read(ip_pipe[0], newipbuf, 64);
+ close(ip_pipe[0]);
+ close(ip_pipe[1]);
+
+ /* cleanup return value string, find the beginning of IP address */
+ newipbuf[63] = '\0'; /* set end condition, just in case */
+ for (retVal = newipbuf; *retVal && (*retVal < '0' || *retVal > '9'); ++retVal) {}
+ /* cleanup return value string, cleanup trailing white space */
+ for (tail = retVal; *tail && ((*tail >= '0' && *tail <= '9') || *tail == '.'); ++tail) {}
+ *tail = '\0';
+
+ if (!is_dotted_quad(retVal))
+ retVal[0]='\0';
+
+ dprintf((stderr, "get_ip_from_cmd, got ip: %s\n", retVal));
+ if (*error != 0)
+ {
+ show_message( "ez-ipupdate: get_ip_from_cmd, got ip: %s, error: %d\n", retVal, *error);
+ }
+
+ return(retVal);
+#else
+ return(-1);
+#endif
+}
+
void handle_sig(int sig)
{
@@ -4395,7 +4530,7 @@
mcheck(NULL);
#endif
- dprintf((stderr, "staring...\n"));
+ dprintf((stderr, "starting...\n"));
program_name = argv[0];
options = 0;
@@ -4473,6 +4608,12 @@
request = strdup(request_over_ride == NULL ? service->default_request : request_over_ride);
dprintf((stderr, "request: %s\n", request));
+ if (get_ip_cmd)
+ {
+ if (interface) free(interface);
+ interface = strdup("getipcmd");
+ }
+
if(service->init != NULL)
{
service->init();
@@ -4512,9 +4653,12 @@
if(!(options & OPT_FOREGROUND))
{
# if HAVE_SYSLOG_H
+ /* If we close these, get_ip_from_cmd() doesn't behave correctly,
+ * because new files opened acts as stdin, stdout, and stderr, screwing
+ * things up.
close(0);
close(1);
- close(2);
+ close(2); */
# endif
if(fork() > 0) { exit(0); } /* parent */
}
Here is what the configuration file looks like:
#!/usr/sbin/ez-ipupdate -c
###
### Default ez-ipupdate configuration file - EDIT WITH CARE
### Use `dpkg-reconfigure ez-ipupdate' to update the debconf-generated lines.
###
### The following lines were generated by debconf
service-type=<your-service-type>
#server=(default)
user=<your-user-and-password>
host=<your-host>
#interface=eth0
#wildcard
#mx=(none)
run-as-user=ez-ipupd
cache-file=/var/cache/ez-ipupdate/default-cache
daemon
### Changes below this line will be preserved on upgrades.
getipcmd=/usr/local/bin/whatsmyip.pl
period=7200
The configuration tells ez-ipupdate to execute whatsmyip.pl to get the IP address. This executable must just print out the IP address of the machine on stdout using any method that works for your situation. I suggest if at all possible to not use web-scraping. Instead, try to contact your router and get your real IP address from there. Unfortunately for my situation, my router isn't straightforward, so I resort to web-scraping. The code I use for whatsmyip.pl is as follows:
#!/usr/bin/perl -wT
use strict;
use LWP::Simple;
my @checkIPURLs = (
"http://www.ipchicken.com",
"http://checkip.dyndns.com",
"http://ipdetect.dnspark.com",
"http://www.whatismyip.org",
"http://ipswift.com",
"http://www.cmyip.com"
);
my $range = scalar(@checkIPURLs);
my $maxLoop = 10;
my $random_number;
my $url;
my $response;
my $gotit;
do {
$gotit = 0;
$random_number = int(rand($range));
$url = $checkIPURLs[$random_number];
$response = get($url);
$response =~ s/<.*?>//gs;
$response =~ s/.*?([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/$1/gs;
$maxLoop--;
$gotit = 1 if ($response =~ m/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/);
} while (!$gotit && $maxLoop > 0);
if ($response =~ m/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/)
{
print "$response\n";
exit 0;
}
else
{
print "\n";
exit 1;
}
That's it. I hope that can help someone.
Thanks