00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include <stdio.h>
00040 #include <syslog.h>
00041 #include <getopt.h>
00042 #include <stdlib.h>
00043 #include <string.h>
00044 #include <signal.h>
00045 #include <errno.h>
00046
00047 #include <unistd.h>
00048 #include <sys/types.h>
00049 #include <sys/wait.h>
00050 #include <sys/socket.h>
00051 #include <sys/ioctl.h>
00052 #include <netinet/in.h>
00053 #include <arpa/inet.h>
00054
00055 #include <linux/types.h>
00056 #include <linux/filter.h>
00057 #include <linux/if_ether.h>
00058 #include <linux/sockios.h>
00059 #include <net/if.h>
00060 #include <netinet/ip.h>
00061 #include <netinet/ip_icmp.h>
00062
00063 #ifndef __UCLIBC__
00064 #include <netpacket/packet.h>
00065 #else
00066 #include <linux/if_packet.h>
00067 #endif
00068
00069 #ifndef min
00070 #define min(a, b) (a < b ? a : b)
00071 #endif
00072
00073
00074
00075
00076
00077 #define IP_ICMP_HEADERS_SIZE (20 + 8)
00078 #define MIN_ICMP_PAYLOAD_SIZE (ICMP_MINLEN + 4)
00079 #define MAX_ICMP_PAYLOAD_SIZE (ETH_DATA_LEN - IP_ICMP_HEADERS_SIZE)
00080 #define IGNORE_PING_PAYLOAD_SIZE -1
00081
00082 #define IFACE_DEFAULT "eth0"
00083
00084 static int ping_timeout = -1;
00085
00086 void usage(FILE *where, char *pgm)
00087 {
00088 fprintf(where,
00089 "Usage: %s [-c] [-e command] [-t secs] "
00090 "[-l bytes] [-i interface] [-n] [-h]\n",
00091 pgm);
00092 }
00093
00094 void ipsetd_timeout(int arg)
00095 {
00096 syslog(LOG_INFO, "Timed out after %ds.", ping_timeout);
00097 exit(EXIT_SUCCESS);
00098 }
00099
00100 void set_ip(int sockfd, unsigned int ipaddr, char *ifr_name_str)
00101 {
00102 int r;
00103
00104 struct sockaddr_in sa;
00105 struct ifreq ifr;
00106
00107 sa.sin_family = AF_INET;
00108 sa.sin_port = 0;
00109 sa.sin_addr.s_addr = ipaddr;
00110
00111 memset(&ifr, 0, sizeof(struct ifreq));
00112 strncpy(ifr.ifr_name, ifr_name_str, IFNAMSIZ);
00113 ifr.ifr_name[IFNAMSIZ - 1] = '\0';
00114 memcpy((char *) &ifr.ifr_addr,
00115 (char *) &sa, sizeof(struct sockaddr));
00116
00117 ifr.ifr_addr.sa_family = AF_INET;
00118
00119 r = ioctl(sockfd, SIOCSIFADDR, &ifr);
00120 if (r < 0) {
00121 perror("set_ip: ioctl");
00122 syslog(LOG_ERR, "ioctl: %s.", sys_errlist[errno]);
00123 exit(EXIT_FAILURE);
00124 }
00125 }
00126
00127 int is_local_ip(int sockfd, in_addr_t new_addr)
00128 {
00129 struct ifconf ifc;
00130 struct ifreq ifreqs[10];
00131 int i;
00132
00133 memset(ifreqs, 0, sizeof ifreqs);
00134 ifc.ifc_len = sizeof ifreqs;
00135 ifc.ifc_req = ifreqs;
00136 if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
00137 perror("is_local_ip: ioctl");
00138 syslog(LOG_ERR, "ioctl: %m");
00139 return 0;
00140 }
00141
00142 for (i = 0; i < sizeof ifreqs / sizeof ifreqs[0]; i++) {
00143 if (ifreqs[i].ifr_name[0] == '\0') {
00144 return 0;
00145 }
00146 if (((struct sockaddr_in *)&ifreqs[i].ifr_addr)->sin_addr.s_addr
00147 == new_addr) {
00148 return 1;
00149 }
00150 }
00151
00152 syslog(LOG_WARNING, "ifreqs too small to determine if address is local,"
00153 " assuming it's not local!");
00154 return 0;
00155 }
00156
00157 int main(int argc, char **argv)
00158 {
00159 int sockfd;
00160 int r;
00161 int c;
00162 int ping_length = IGNORE_PING_PAYLOAD_SIZE;
00163 int change_ip_on_ping = 0;
00164 char newip_exec[256] = "";
00165 char iface[IFNAMSIZ] = IFACE_DEFAULT;
00166
00167 struct ifreq ifr;
00168 struct sockaddr_ll sl;
00169 int bind_to_interface = 0;
00170 int no_daemon = 0;
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188 openlog("ipsetd", LOG_PID, LOG_USER);
00189
00190 while (1) {
00191 c = getopt(argc, argv, "t:e:l:ci:nh");
00192
00193 if (c == -1) {
00194
00195 break;
00196 }
00197
00198 switch (c) {
00199 case 't':
00200
00201 if (optarg) {
00202 ping_timeout = atoi(optarg);
00203 if (ping_timeout < 1)
00204 {
00205 fprintf(stderr,
00206 "Invalid timeout argument.\n");
00207 exit(EXIT_FAILURE);
00208 }
00209 }
00210 break;
00211
00212 case 'e':
00213
00214 if (optarg) {
00215 strncpy(newip_exec, optarg,
00216 min(strlen(optarg), sizeof(newip_exec)));
00217 newip_exec[sizeof(newip_exec) - 1] = '\0';
00218 }
00219 break;
00220
00221 case 'l':
00222
00223 if (optarg) {
00224 ping_length = atoi(optarg);
00225 if ((ping_length < MIN_ICMP_PAYLOAD_SIZE) ||
00226 (ping_length > MAX_ICMP_PAYLOAD_SIZE)) {
00227 fprintf(stderr,
00228 "Invalid echo request payload "
00229 "size %d (min %d, max %d).\n",
00230 ping_length,
00231 MIN_ICMP_PAYLOAD_SIZE,
00232 MAX_ICMP_PAYLOAD_SIZE);
00233 exit(EXIT_FAILURE);
00234 }
00235 }
00236 break;
00237
00238 case 'c':
00239
00240 change_ip_on_ping = 1;
00241 break;
00242
00243 case 'i':
00244 bind_to_interface = 1;
00245 if (optarg) {
00246 strncpy(iface, optarg, IFNAMSIZ);
00247 iface[IFNAMSIZ - 1] = '\0';
00248 }
00249 break;
00250
00251 case 'n':
00252 no_daemon = 1;
00253 break;
00254
00255 case 'h':
00256 usage(stdout, argv[0]);
00257 exit(EXIT_SUCCESS);
00258
00259 default:
00260 usage(stderr, argv[0]);
00261 exit(EXIT_FAILURE);
00262 }
00263 }
00264
00265
00266
00267
00268
00269
00270 sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
00271
00272 if (sockfd < 0) {
00273 perror("socket");
00274 fprintf(stderr, "socket: %s.\n", sys_errlist[errno]);
00275 exit(EXIT_FAILURE);
00276 }
00277
00278 if (bind_to_interface) {
00279 memset(&ifr, 0, sizeof(ifr));
00280 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
00281 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
00282 if (ioctl(sockfd, SIOCGIFINDEX, &ifr) < 0) {
00283 perror("SIOCGIFINDEX");
00284 fprintf(stderr, "SIOCGIFINDEX: %s.\n",
00285 sys_errlist[errno]);
00286 exit(EXIT_FAILURE);
00287 }
00288
00289 memset(&sl, 0, sizeof(sl));
00290 sl.sll_family = AF_PACKET;
00291 sl.sll_protocol = htonl(ETH_P_IP);
00292 sl.sll_ifindex = ifr.ifr_ifindex;
00293 if (bind(sockfd, (struct sockaddr *)&sl, sizeof(sl))) {
00294 perror("bind");
00295 fprintf(stderr, "bind: %s.\n", sys_errlist[errno]);
00296 exit(EXIT_FAILURE);
00297 }
00298 }
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309 if (!no_daemon && (daemon(0, 0) < 0)) {
00310 perror("daemon");
00311 exit(EXIT_FAILURE);
00312 }
00313
00314 syslog(LOG_INFO, "Timeout in %d s.", ping_timeout);
00315 syslog(LOG_INFO, "Expecting echo request payload %d bytes.",
00316 ping_length);
00317 syslog(LOG_INFO, "On echo request arrival, execute %s.", newip_exec);
00318
00319 if (ping_timeout > 0) {
00320 signal(SIGALRM, ipsetd_timeout);
00321 alarm(ping_timeout);
00322 }
00323
00324
00325 while (1) {
00326 struct iphdr iph;
00327 struct icmphdr ih;
00328 struct in_addr new_ip;
00329 struct sockaddr_ll from;
00330 socklen_t fromlen;
00331 int ping_packet_len;
00332 unsigned char buf[2000];
00333
00334 fromlen = sizeof(from);
00335 r = recvfrom(sockfd, buf, sizeof(buf), 0,
00336 (struct sockaddr *)&from, &fromlen);
00337
00338 if (r < 0 || from.sll_pkttype != PACKET_HOST) {
00339 continue;
00340 }
00341
00342 memcpy(&iph, buf + sizeof(struct ethhdr), sizeof(struct iphdr));
00343
00344 memcpy(&ih, buf + sizeof(struct ethhdr) + sizeof(struct iphdr), sizeof(struct icmphdr));
00345
00346 if(iph.protocol != 0x01)
00347 continue;
00348
00349 if(ih.type != ICMP_ECHO)
00350 continue;
00351 new_ip.s_addr = iph.daddr;
00352 ping_packet_len = ntohs(iph.tot_len) - IP_ICMP_HEADERS_SIZE;
00353
00354 if (((ping_length == IGNORE_PING_PAYLOAD_SIZE) ||
00355 (ping_length == ping_packet_len)) &&
00356 !is_local_ip(sockfd, new_ip.s_addr) &&
00357 !is_local_ip(sockfd, iph.saddr)) {
00358 if (change_ip_on_ping) {
00359 syslog(LOG_INFO, "Changing IP address "
00360 "on interface %s to %s.", iface,
00361 inet_ntoa(new_ip));
00362 set_ip(sockfd, new_ip.s_addr, iface);
00363 }
00364
00365 if (newip_exec[0]) {
00366 char buffer[10];
00367
00368
00369 alarm(0);
00370 setenv("NEW_IPADDR", inet_ntoa(new_ip), 1);
00371 snprintf(buffer, sizeof(buffer), "%lu",
00372 (unsigned long)(ntohl(new_ip.s_addr) >> 24));
00373 setenv("NEW_IP_ANET", buffer, 1);
00374 setenv("IFNAME", iface, 1);
00375
00376 r = system(newip_exec);
00377 if (r == -1) {
00378
00379 syslog(LOG_ERR, "%s execution failed.",
00380 newip_exec);
00381 exit(EXIT_FAILURE);
00382 }
00383 if (WIFEXITED(r) != 0) {
00384
00385 syslog(LOG_INFO, "%s exit with %d.",
00386 newip_exec, WEXITSTATUS(r));
00387 exit(EXIT_SUCCESS);
00388 }
00389 if (WIFSIGNALED(r)) {
00390
00391 syslog(LOG_ERR,
00392 "%s died with signal %d.",
00393 newip_exec, WTERMSIG(r));
00394 exit(EXIT_FAILURE);
00395 }
00396 }
00397
00398 return 0;
00399 }
00400 }
00401
00402 return 0;
00403 }