X-Git-Url: https://the.earth.li/gitweb/?p=mqtt-arp.git;a=blobdiff_plain;f=mqtt-arp.c;h=2836366b40391dfa6d9373e8fb9e316268f91d28;hp=114e0efff80889fc96e5d0fd406301893f00be38;hb=939e344284056025f919de31e56ac4e7a7ea71e2;hpb=35f4b6d147a8ab61fadc8a72118c18bd930e9160 diff --git a/mqtt-arp.c b/mqtt-arp.c index 114e0ef..2836366 100644 --- a/mqtt-arp.c +++ b/mqtt-arp.c @@ -16,7 +16,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include +#include #include +#include #include #include #include @@ -37,6 +40,7 @@ #define MQTT_PORT 8883 #define MQTT_TOPIC "location/by-mac" #define LOCATION "home" +#define CONFIG_FILE "/etc/mqtt-arp.conf" /* How often (in seconds) to report that we see a device */ #define REPORT_INTERVAL (2 * 60) @@ -64,6 +68,12 @@ struct ma_config { }; bool debug = false; +bool want_shutdown = false; + +void shutdown_request(int signal) +{ + want_shutdown = true; +} bool mac_compare(uint8_t *a, uint8_t *b) { @@ -167,7 +177,7 @@ void main_loop(struct ma_config *config, struct mosquitto *mosq, int sock) hdr = (struct nlmsghdr *) buf; nd = (struct ndmsg *) (hdr + 1); - while (1) { + while (!want_shutdown) { received = recv(sock, buf, sizeof(buf), 0); if (debug) { t = time(NULL); @@ -190,19 +200,20 @@ void main_loop(struct ma_config *config, struct mosquitto *mosq, int sock) nd->ndm_type); } attr = (struct nlattr *) (nd + 1); - while (attr->nla_len > 0) { - data = (((uint8_t *) attr) + 4); + while (((uint8_t *) attr - buf) < hdr->nlmsg_len) { + data = (((uint8_t *) attr) + NLA_HDRLEN); if (attr->nla_type == NDA_LLADDR && nd->ndm_state == NUD_REACHABLE) { mqtt_mac_presence(config, mosq, data, true); } - attr = (struct nlattr *) - (((uint8_t *) attr) + attr->nla_len); + attr = (struct nlattr *) (((uint8_t *) attr) + + NLA_ALIGN(attr->nla_len)); } break; case RTM_DELNEIGH: case RTM_GETNEIGH: + break; default: printf("Unknown message type: %d\n", hdr->nlmsg_type); } @@ -275,6 +286,61 @@ int netlink_init(void) return sock; } +int read_config(char *file, struct ma_config *config, int *macs) +{ + FILE *f; + char line[256]; + int i; + + f = fopen(file, "r"); + if (f == NULL) + return errno; + +#define INT_OPTION(opt, var) \ + if (strncmp(line, opt " ", sizeof(opt)) == 0) { \ + var = atoi(&line[sizeof(opt)]); \ + } +#define STRING_OPTION(opt, var) \ + if (strncmp(line, opt " ", sizeof(opt)) == 0) { \ + var = strdup(&line[sizeof(opt)]); \ + } + + while (fgets(line, sizeof(line), f) != NULL) { + for (i = strlen(line) - 1; i >= 0 && isspace(line[i]); i--) + line[i] = '\0'; + if (line[0] == '\0' || line[0] == '#') + continue; + + if (strncmp(line, "mac ", 4) == 0) { + if (*macs >= MAX_MACS) { + printf("Can only accept %d MAC addresses to" + " watch for.\n", MAX_MACS); + exit(EXIT_FAILURE); + } + sscanf(&line[4], + "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + &config->macs[*macs].mac[0], + &config->macs[*macs].mac[1], + &config->macs[*macs].mac[2], + &config->macs[*macs].mac[3], + &config->macs[*macs].mac[4], + &config->macs[*macs].mac[5]); + config->macs[*macs].valid = true; + (*macs)++; + } else + STRING_OPTION("mqtt_host", config->mqtt_host) else + INT_OPTION("mqtt_port", config->mqtt_port) else + STRING_OPTION("mqtt_user", config->mqtt_username) else + STRING_OPTION("mqtt_pass", config->mqtt_password) else + STRING_OPTION("mqtt_topic", config->mqtt_topic) else + STRING_OPTION("location", config->location) else + STRING_OPTION("capath", config->capath) + } + fclose(f); + + return 0; +} + struct option long_options[] = { { "capath", required_argument, 0, 'c' }, { "host", required_argument, 0, 'h' }, @@ -300,6 +366,9 @@ int main(int argc, char *argv[]) bzero(&config, sizeof(config)); config.mqtt_port = MQTT_PORT; + /* Read config before parsing command line */ + read_config(CONFIG_FILE, &config, &macs); + while (1) { c = getopt_long(argc, argv, "c:h:l:m:p:P:t:u:v", long_options, &option_index); @@ -358,12 +427,20 @@ int main(int argc, char *argv[]) if (!config.mqtt_host) config.mqtt_host = MQTT_HOST; if (!config.mqtt_topic) - config.mqtt_host = MQTT_TOPIC; + config.mqtt_topic = MQTT_TOPIC; if (!config.location) - config.mqtt_host = LOCATION; + config.location = LOCATION; + + signal(SIGTERM, shutdown_request); sock = netlink_init(); mosq = mqtt_init(&config); main_loop(&config, mosq, sock); + + mosquitto_disconnect(mosq); + mosquitto_loop_stop(mosq, true); + mosquitto_destroy(mosq); + mosquitto_lib_cleanup(); + close(sock); }