X-Git-Url: https://the.earth.li/gitweb/?a=blobdiff_plain;ds=sidebyside;f=mqtt-arp.c;h=bc65fbb2acf63088be69342005ba892bc72fc09e;hb=670acb35f09c59e599f4fc7371b33613e567f830;hp=6c83ccacf87b107f0fe6503a83c5ff71f070056e;hpb=ce532d3405a9d7c45a7a9ab17a622c8703df5612;p=mqtt-arp.git
diff --git a/mqtt-arp.c b/mqtt-arp.c
index 6c83cca..bc65fbb 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,13 +286,70 @@ 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' },
{ "location", required_argument, 0, 'l' },
{ "mac", required_argument, 0, 'm' },
+ { "password", required_argument, 0, 'P' },
{ "port", required_argument, 0, 'p' },
{ "topic", required_argument, 0, 't' },
+ { "username", required_argument, 0, 'u' },
{ "verbose", no_argument, 0, 'v' },
{ 0, 0, 0, 0 }
};
@@ -293,13 +361,16 @@ int main(int argc, char *argv[])
struct ma_config config;
int option_index = 0;
int macs = 0;
- char c;
+ int c;
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:t:v",
+ c = getopt_long(argc, argv, "c:h:l:m:p:P:t:u:v",
long_options, &option_index);
if (c == -1)
@@ -329,13 +400,21 @@ int main(int argc, char *argv[])
&config.macs[macs].mac[3],
&config.macs[macs].mac[4],
&config.macs[macs].mac[5]);
+ config.macs[macs].valid = true;
+ macs++;
break;
case 'p':
config.mqtt_port = atoi(optarg);
break;
+ case 'P':
+ config.mqtt_password = optarg;
+ break;
case 't':
config.mqtt_topic = optarg;
break;
+ case 'u':
+ config.mqtt_username = optarg;
+ break;
case 'v':
debug = true;
break;
@@ -348,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);
}