bool filterIfAddrMsg(struct ifaddrmsg const ifa, struct AddrFilter const filter){ return checkFilterAf(filter, ifa.ifa_family) && ifa.ifa_index == filter.iface && (ifa.ifa_scope == RT_SCOPE_UNIVERSE || ifa.ifa_scope == RT_SCOPE_SITE) && !(ifa.ifa_flags & IFA_F_DEPRECATED); }
int main(int const argc, char** argv) { struct AddrFilter filter = {.allow_private = false}; int (* addr_processor)(struct IPAddr); // Deal with options const char short_opts[] = "vVh46pa"; struct option long_opts[] = { {"allow-private", no_argument, 0, 'p'}, {"process-all", no_argument, 0, 'a'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, }; bool verbosity = 0; bool process_all = false; int opt_index = 0; char opt; while ((opt = getopt_long(argc, argv, short_opts, long_opts, &opt_index)) != -1) { switch (opt) { case 'a': process_all = true; break; case 'v': verbosity = 1; break; case 'V': puts(version); return EXIT_SUCCESS; case '4': addFilterAf(&filter, AF_INET); break; case '6': addFilterAf(&filter, AF_INET6); break; case 'p': filter.allow_private = true; break; case 'h': printUsage(); return EXIT_SUCCESS; default: printUsage(); return EXIT_USAGE; } } // Listen for all changes if none specified. if (filter.num_af == 0){ addFilterAf(&filter, AF_INET); addFilterAf(&filter, AF_INET6); } switch ((argc - optind)){ case 1: addr_processor = printAddr; break; case 2: setUrl(argv[optind + 1]); addr_processor = webUpdate; break; default: puts("Usage:\n"); printUsage(); return EXIT_USAGE; } char const * const iface_name = argv[optind]; filter.iface = if_nametoindex(iface_name); if (!filter.iface) { fprintf(stderr, "Error resolving interface %s: %s\n", iface_name, strerror(errno)); return EXIT_FAILURE; } if (verbosity){ puts("Running in verbose mode."); printf("Listening on interfaces: %s (#%d)\n", iface_name, filter.iface); fputs("Listening for address changes in:", stdout); if (checkFilterAf(filter, AF_INET)) printf(" IPv4"); if (checkFilterAf(filter, AF_INET6)) printf(" IPv6"); puts(""); } // Prepare monitoring, cleanup necessary if exiting after this point. struct MonitorState state; if (!initState(filter, &state, 1024)){ perror("Couldn't set up for monitoring"); return EXIT_FAILURE; } // Main loop pid_t child = -1; do { struct IPAddr new_addr = nextAddr(filter, &state); if (child != -1){ // Make sure kill isn't called on first loop. if (!process_all) kill(child, termsig); int status; if (waitpid(child, &status, 0) == -1){ perror("Error waiting for child"); break; } if (!childOK(status)) break; } if (new_addr.af == AF_MAX){ perror("An error occurred while waiting for a new IP"); break; } else if (new_addr.af == AF_UNSPEC) { fputs("Netlink socket closed by kernel.", stderr); break; } // TODO: Could use exec child = fork(); if (child == -1){ perror("Could not fork to process new address."); break; } else if (!child){ close(state.socket); // Make sure to set CLOEXEC if changing to exec. return addr_processor(new_addr); } } while (true); close(state.socket); free(state.buf); return EXIT_FAILURE; }