mirror of https://github.com/sfeakes/AqualinkD.git
192 lines
4.9 KiB
C
192 lines
4.9 KiB
C
|
|
#define _GNU_SOURCE 1 // for strcasestr
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include <ifaddrs.h>
|
|
#include <net/if.h>
|
|
#include <netpacket/packet.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <unistd.h>
|
|
|
|
#include "net_interface.h"
|
|
#include "utils.h"
|
|
#include "config.h"
|
|
|
|
#define RESOLV_CONF_FILE_NAME "/etc/resolv.conf"
|
|
|
|
const char *get_ip_address_of_nameserver()
|
|
{
|
|
FILE *fp;
|
|
char line[512];
|
|
bool found = false;
|
|
|
|
// 27 chars for ipv4 and 56 for ipv6
|
|
// udp://x.x.x.x:53
|
|
// udp://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:53
|
|
static char nameserver[60];
|
|
|
|
if ((fp = fopen(RESOLV_CONF_FILE_NAME, "r")) == NULL)
|
|
{
|
|
found = false;
|
|
}
|
|
else
|
|
{
|
|
/* Try to figure out what nameserver to use */
|
|
for (found = false; fgets(line, sizeof(line), fp) != NULL;)
|
|
{
|
|
unsigned int a, b, c, d;
|
|
if (sscanf(line, "nameserver %u.%u.%u.%u", &a, &b, &c, &d) == 4)
|
|
{
|
|
snprintf(nameserver, 60, "udp://%u.%u.%u.%u:53", a, b, c, d);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
(void)fclose(fp);
|
|
}
|
|
|
|
if (found)
|
|
return nameserver;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
void url_ptrs(char *url, char **protocol, char **port)
|
|
{
|
|
*protocol = NULL;
|
|
*port = NULL;
|
|
char *ptr = (char *)url;
|
|
|
|
for (int i = 0; i < strlen(ptr); i++)
|
|
{
|
|
if (ptr[i] == ':' && *protocol == NULL)
|
|
{
|
|
*protocol = &ptr[i];
|
|
}
|
|
else if (ptr[i] == ':' && *protocol != NULL)
|
|
{
|
|
*port = &ptr[i+1];
|
|
}
|
|
}
|
|
}
|
|
|
|
const net_iface *get_first_valid_interface()
|
|
{
|
|
static net_iface info;
|
|
static bool found = false;
|
|
struct ifaddrs *ifaddr, *ifa;
|
|
int family;
|
|
|
|
if (found)
|
|
goto end;
|
|
|
|
if (getifaddrs(&ifaddr) == -1)
|
|
{
|
|
perror("getifaddrs");
|
|
return NULL;
|
|
}
|
|
|
|
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
|
|
{
|
|
if (!ifa->ifa_addr)
|
|
continue;
|
|
|
|
family = ifa->ifa_addr->sa_family;
|
|
|
|
if (!found && family == AF_INET && !(ifa->ifa_flags & IFF_LOOPBACK))
|
|
{
|
|
struct sockaddr_in *sa = (struct sockaddr_in *)ifa->ifa_addr;
|
|
inet_ntop(AF_INET, &sa->sin_addr, info.ip, sizeof(info.ip));
|
|
strncpy(info.name, ifa->ifa_name, sizeof(info.name) - 1);
|
|
info.name[sizeof(info.name) - 1] = '\0';
|
|
found = true;
|
|
}
|
|
|
|
if (family == AF_PACKET)
|
|
{
|
|
struct sockaddr_ll *s = (struct sockaddr_ll *)ifa->ifa_addr;
|
|
if (s->sll_halen == 6 &&
|
|
(!found || strcmp(info.name, ifa->ifa_name) == 0))
|
|
{
|
|
snprintf(info.mac, sizeof(info.mac),
|
|
"%02x:%02x:%02x:%02x:%02x:%02x",
|
|
(unsigned char)s->sll_addr[0],
|
|
(unsigned char)s->sll_addr[1],
|
|
(unsigned char)s->sll_addr[2],
|
|
(unsigned char)s->sll_addr[3],
|
|
(unsigned char)s->sll_addr[4],
|
|
(unsigned char)s->sll_addr[5]);
|
|
|
|
snprintf(info.rawmac, sizeof(info.rawmac),
|
|
"%02x%02x%02x%02x%02x%02x",
|
|
(unsigned char)s->sll_addr[0],
|
|
(unsigned char)s->sll_addr[1],
|
|
(unsigned char)s->sll_addr[2],
|
|
(unsigned char)s->sll_addr[3],
|
|
(unsigned char)s->sll_addr[4],
|
|
(unsigned char)s->sll_addr[5]);
|
|
}
|
|
}
|
|
}
|
|
|
|
freeifaddrs(ifaddr);
|
|
|
|
if (found){
|
|
char *protocol, *port;
|
|
url_ptrs(_aqconfig_.listen_address, &protocol, &port);
|
|
|
|
if (port != NULL && protocol != NULL) {
|
|
sprintf(info.url, "%.*s://%s:%s", (int)(protocol - _aqconfig_.listen_address), _aqconfig_.listen_address, info.ip, port);
|
|
sprintf(info.localurl, "%.*s://localhost:%s", (int)(protocol - _aqconfig_.listen_address), _aqconfig_.listen_address, port);
|
|
} else {
|
|
LOG(NET_LOG, LOG_ERR,"Could not understand URL '%s' (unable to get protocol & port) \n",_aqconfig_.listen_address);
|
|
}
|
|
|
|
if (_aqconfig_.listen_address[(int)(protocol - _aqconfig_.listen_address)-1] == 's' ||
|
|
_aqconfig_.listen_address[(int)(protocol - _aqconfig_.listen_address)-1] == 'S')
|
|
info.isLocalurlTLS = true;
|
|
else
|
|
info.isLocalurlTLS = false;
|
|
|
|
LOG(NET_LOG, LOG_DEBUG, "Interface %s = %s, %s\n", info.name, info.ip, info.mac);
|
|
} else {
|
|
LOG(NET_LOG, LOG_ERR,"Could not find a valid network interface");
|
|
}
|
|
|
|
end:
|
|
|
|
return found ? &info : NULL;
|
|
}
|
|
|
|
|
|
/* In future maybe remove mqtt_id from aq_config and use static here */
|
|
char *generate_mqtt_id() {
|
|
static char ID[MQTT_ID_LEN+1];
|
|
static bool created=false;
|
|
|
|
if (!created){
|
|
extern char *__progname; // glibc populates this
|
|
int i;
|
|
strncpy(ID, basename(__progname), MQTT_ID_LEN);
|
|
i = strlen(ID);
|
|
|
|
if ( i > 9) { i=9; } // cut down to 9 characters (aqualinkd)
|
|
if (i < MQTT_ID_LEN) {
|
|
ID[i++] = '_';
|
|
const net_iface *info = get_first_valid_interface();
|
|
if (info->rawmac != NULL)
|
|
sprintf(&ID[i], "%.*s", (MQTT_ID_LEN-i), info->rawmac);
|
|
else
|
|
sprintf(&ID[i], "%.*d", (MQTT_ID_LEN-i), getpid());
|
|
}
|
|
|
|
ID[MQTT_ID_LEN] = '\0';
|
|
created = true;
|
|
}
|
|
|
|
return ID;
|
|
} |