Skip to content

Commit

Permalink
Configuration Improvements
Browse files Browse the repository at this point in the history
Improve searching default locations for config file
Fix change of has table size during config reload
Add recalloc()
  • Loading branch information
Uglymotha committed Aug 13, 2024
1 parent e4d91ae commit 3c9b446
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 87 deletions.
8 changes: 2 additions & 6 deletions src/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ void acceptCli(void)
return;
}
}

if (buf[0] == 'r') {
logRouteTable("", buf[1] == 'h' ? 0 : 1, fd, addr, mask);
} else if ((buf[0] == 'i' || buf[0] == 'f') && len > 2 && ! (IfDp = getIf(0, &buf[buf[1] == 'h' ? 3 : 2], 2))) {
Expand Down Expand Up @@ -178,7 +177,7 @@ void cliCmd(char *cmd, int tbl) {
struct sigaction sa;
struct stat st;
struct sockaddr_un srv_sa;
char buf[CLI_CMD_BUF+1] = "", paths[sizeof(RUN_PATHS)] = RUN_PATHS, *path, tpath[128];
char buf[CLI_CMD_BUF+1] = "", *path, tpath[128];

sa.sa_handler = cliSignalHandler;
sa.sa_flags = 0; /* Interrupt system calls */
Expand All @@ -195,7 +194,7 @@ void cliCmd(char *cmd, int tbl) {
#endif

// Check for daemon socket location.
path = strtok(paths, " ");
path = strtok(RUN_PATHS, " ");
while (path) {
sprintf(tpath, "%s/%s/root", path, fileName);
if (lstat(tpath, &st) == 0 && (S_ISLNK(st.st_mode) || S_ISDIR(st.st_mode))) {
Expand All @@ -222,15 +221,12 @@ void cliCmd(char *cmd, int tbl) {
fprintf(stderr, "Cannot open daemon socket (%s). %s\n", srv_sa.sun_path, strerror(errno));
exit(-1);
}

if (send(srv_fd, cmd, strlen(cmd), 0) < 0) {
fprintf(stderr, "Cannot send command. %s\n", strerror(errno));
exit(-1);
}

// Receive the daemon's answer. It will be closed by one single byte.
for (int len = 0; (len = recv(srv_fd, &buf, CLI_CMD_BUF, 0)) > 0; buf[len] = '\0', fprintf(stdout, "%s", buf));

close(srv_fd);
}

Expand Down
35 changes: 14 additions & 21 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ static const char *options = " include phyint user group chroot defaultquickleav
static const char *phyintopt = " table updownstream upstream downstream disabled proxylocalmc noproxylocalmc quickleave noquickleave ratelimit threshold nocksumverify cksumverify noquerierelection querierelection querierip querierver robustnessvalue queryinterval queryrepsonseinterval lastmemberinterval lastmembercount defaultfilter filter altnet whitelist disableipmrules";

// Daemon Configuration.
static struct Config conf, oldconf;
static struct Config conf, oldconf;
extern volatile sig_atomic_t sighandled; // From igmpv3proxy.c signal handler.

// Structures to keep vif configuration and black/whitelists.
static struct vifConfig *vifConf = NULL, *ovifConf = NULL;
Expand Down Expand Up @@ -360,7 +361,6 @@ static inline bool parsePhyintToken(char *token) {
LOG(LOG_WARNING, 0, "Config: You should at least name your interfeces.");
return false;
}

// Find existing or create new vifConf.
for (tmpPtr = vifConf; tmpPtr && strncmp(tmpPtr->name, token + 1, IF_NAMESIZE); tmpPtr = tmpPtr->next);
if (! tmpPtr) {
Expand Down Expand Up @@ -539,7 +539,6 @@ static inline bool parsePhyintToken(char *token) {
// Return false if error in interface config was detected. freeConfig will cleanup.
if (logwarning)
return false;

// Check Query response interval and adjust if necessary (query response must be <= query interval).
if ((tmpPtr->qry.ver != 3 ? tmpPtr->qry.responseInterval : getIgmpExp(tmpPtr->qry.responseInterval, 0)) / 10
> tmpPtr->qry.interval) {
Expand All @@ -551,7 +550,6 @@ static inline bool parsePhyintToken(char *token) {
LOG(LOG_NOTICE, 0, "Config (%s): Setting default query interval to %ds. Default response interval %.1fs",
tmpPtr->name, tmpPtr->qry.interval, f);
}

if (!tmpPtr->noDefaultFilter)
*filP = conf.defaultFilters;

Expand All @@ -575,14 +573,13 @@ bool loadConfig(char *cfgFile) {
char *token = NULL;
struct stat st;

// Initialize common config on first entry.
if (conf.cnt++ == 0) {
// Initialize common config on first entry.
logwarning = 0;
initCommonConfig();
filP = &conf.defaultFilters;
rateP = &conf.defaultRates;
}

if (conf.cnt == 0xFF) {
// Check recursion and return if exceeded.
LOG(LOG_WARNING, 0, "Config: Too many includes (%d) while loading '%s'.", 0xFF, cfgFile);
Expand All @@ -599,7 +596,6 @@ bool loadConfig(char *cfgFile) {
free(d[n]);
}
free(d);
//return !logwarning;
} else if (!S_ISREG(st_mode) || ! (confFilePtr = configFile(cfgFile, 1))) {
// Open config file.
LOG(LOG_WARNING, errno, "Config: Failed to open config file '%s'.", cfgFile);
Expand Down Expand Up @@ -643,7 +639,7 @@ bool loadConfig(char *cfgFile) {
LOG(LOG_WARNING, 0, "Config: Failed to include config from '%s'.", token + 1);
configFile(confFilePtr, 2);
} else if (strcmp(" chroot", token) == 0 && nextToken(token) && (STARTUP || (token[1] = '\0'))) {
if (! (conf.chroot = malloc(strlen(token)))) // Freed by signalHandler() or Self
if (! (conf.chroot = malloc(strlen(token)))) // Freed by igmpProxyCleanUp() or Self
LOG(LOG_ERR, eNOMEM, "Config: Out of Memory.");
memcpy(conf.chroot, token + 1, strlen(token));
if (stat(token + 1, &st) != 0 && !(stat(dirname(token + 1), &st) == 0 && mkdir(conf.chroot, 0770) == 0)) {
Expand Down Expand Up @@ -726,8 +722,8 @@ bool loadConfig(char *cfgFile) {
if (intToken < 8 || intToken > 131072)
LOG(LOG_WARNING, 0, "Config: hashtablesize must be 8 to 131072 bytes (multiples of 8).");
else {
conf.dHostsHTSize = (intToken - intToken % 8) * 8;
LOG(LOG_NOTICE, 0, "Config: Hash table size for quickleave is %d.", conf.dHostsHTSize / 8);
conf.dHostsHTSize = intToken % 8 == 0 ? intToken : intToken + (8 - (intToken % 8));
LOG(LOG_NOTICE, 0, "Config: Hash table size for quickleave is %d.", conf.dHostsHTSize);
}

} else if (strcmp(" defaultupdown", token) == 0) {
Expand Down Expand Up @@ -862,7 +858,7 @@ bool loadConfig(char *cfgFile) {
else if ((! ((fp = fopen(token + 1, "w")) && (t = token + 1)) && ! (fp = fopen(t, "w"))) || fclose(fp) != 0)
LOG(LOG_WARNING, errno, "Config: Cannot open log file '%s'.", token + 1);
else if (! (conf.logFilePath = realloc(conf.logFilePath, strlen(token))))
// Freed by signalHandler()
// Freed by igmpProxyCleanUp() or igmpProxyInit()
LOG(LOG_ERR, eNOMEM, "loadConfig: Out of Memory.");
else {
strcpy(conf.logFilePath, t);
Expand All @@ -888,12 +884,10 @@ bool loadConfig(char *cfgFile) {
// Token may be " " if parsePhyintToken() returns without valid token.
LOG(LOG_WARNING, 0, "Config: Unknown token '%s' in config file '%s'.", token + 1, cfgFile);
}

// Close the configfile. When including files, we're done. Decrease count when file has loaded. Reset common flag.
_free(token, var, MAX_TOKEN_LENGTH + READ_BUFFER_SIZE + 2 * sizeof(uint32_t)); // Alloced by self
if (confFilePtr && (confFilePtr = configFile(NULL, 0)))
LOG(LOG_WARNING, errno, "Config: Failed to close config file (%d) '%s'.", conf.cnt, cfgFile);

if (--conf.cnt > 0 || logwarning)
return !logwarning;

Expand All @@ -911,25 +905,24 @@ bool loadConfig(char *cfgFile) {
}

// Check if buffer sizes have changed.
if (CONFRELOAD && (conf.kBufsz != oldconf.kBufsz || conf.pBufsz != oldconf.pBufsz))
if (mrt_tbl >= 0 && (CONFRELOAD || SHUP) && (conf.kBufsz != oldconf.kBufsz || conf.pBufsz != oldconf.pBufsz)) {
initIgmp(false);

initIgmp(true);
}
// Check rescanvif status and start or clear timers if necessary.
if (conf.rescanVif && timers.rescanVif == 0) {
timers.rescanVif = timer_setTimer(conf.rescanVif * 10, "Rebuild Interfaces", rebuildIfVc, &timers.rescanVif);
} else if (!conf.rescanVif && timers.rescanVif != 0) {
timer_clearTimer(timers.rescanVif);
timers.rescanVif = 0;
}

// Check rescanconf status and start or clear timers if necessary.
if (conf.rescanConf && timers.rescanConf == 0) {
timers.rescanConf = timer_setTimer(conf.rescanConf * 10, "Reload Configuration", reloadConfig, &timers.rescanConf);
} else if (!conf.rescanConf && timers.rescanConf != 0) {
timer_clearTimer(timers.rescanConf);
timers.rescanConf = 0;
}

// Check bwcontrol status and start or clear timers if necessary..
if (oldconf.bwControlInterval != conf.bwControlInterval) {
timer_clearTimer(timers.bwControl);
Expand All @@ -941,7 +934,7 @@ bool loadConfig(char *cfgFile) {
LOG(LOG_WARNING, errno, "Config: MRT_API_CONFIG Failed. Disabling bandwidth control.");
conf.bwControlInterval = 0;
} else if (!STARTUP)
clearGroups(getConfig);
clearGroups(CONF);
#endif
if (conf.bwControlInterval)
timers.bwControl = timer_setTimer(conf.bwControlInterval * 10, "Bandwidth Control",
Expand Down Expand Up @@ -1125,10 +1118,10 @@ void configureVifs(void) {
}

// Check if quickleave was enabled or disabled due to config change.
if ((CONFRELOAD || SHUP) && oldconf.dHostsHTSize != conf.dHostsHTSize) {
LOG(LOG_WARNING, 0, "configureVifs: Downstream host hashtable size changed from %d to %d, reinitializing group tables.",
if ((CONFRELOAD || SHUP) && oldconf.dHostsHTSize != conf.dHostsHTSize && mrt_tbl >= 0) {
LOG(LOG_WARNING, 0, "configureVifs: Downstream host hashtable size changed from %d to %d, restarting.",
oldconf.dHostsHTSize, conf.dHostsHTSize);
clearGroups(&conf);
sighandled |= GOT_SIGURG;
}

// All vifs created / updated, check if there is an upstream and at least one downstream.
Expand Down
2 changes: 0 additions & 2 deletions src/ifvc.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,9 @@ void rebuildIfVc(uint64_t *tid) {
sigstatus |= GOT_SIGUSR2;
if (! IfDescL || IFREBUILD || SHUP || STARTUP)
buildIfVc();

// Call configureVifs to link the new IfDesc table.
LOG(LOG_INFO,0,"rebuildIfVc: Configuring MC vifs.");
configureVifs();

// Free removed interfaces.
freeIfDescL();

Expand Down
30 changes: 15 additions & 15 deletions src/igmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ int initIgmp(bool activate) {
if (!activate) {
_free(rcv_buf, rcv, memuse.rcv); // Alloced by Self
_free(snd_buf, snd, memuse.snd); // Alloced by Self
if (fd != -1 && !RESTART)
if (fd != -1 && !RESTART && !SHUP && !CONFRELOAD)
fd = k_disableMRouter();
return fd;
}
Expand Down Expand Up @@ -180,12 +180,12 @@ void acceptIgmp(int fd) {
#endif
#ifdef IGMPMSG_WRONGVIF
case IGMPMSG_WRONGVIF:
LOG(LOG_NOTICE, 0, "Received WRONGVIF Upcall for Src %s Dst %s on %s.",
LOG(LOG_NOTICE, 0, "WRONGVIF Upcall for Src %s Dst %s on %s.",
inetFmt(igmpMsg->im_src.s_addr, 1), inetFmt(igmpMsg->im_dst.s_addr, 2), IfDp->Name);
return;
#endif
default:
LOG(LOG_NOTICE, 0, "Received unsupported upcall %d.", igmpMsg->im_msgtype);
LOG(LOG_NOTICE, 0, "Unsupported upcall %d.", igmpMsg->im_msgtype);
return;
}
} else for (cmsgPtr = CMSG_FIRSTHDR(&msgHdr); cmsgPtr; cmsgPtr = CMSG_NXTHDR(&msgHdr, cmsgPtr))
Expand All @@ -211,14 +211,14 @@ void acceptIgmp(int fd) {
register uint16_t cksum = igmp->igmp_cksum;
igmp->igmp_cksum = 0;
if (iphdrlen + ipdatalen != recvlen)
LOG(LOG_NOTICE, 0, "acceptIgmp: received packet from %s shorter (%u bytes) than hdr+data length (%u+%u).",
inetFmt(src, 1), recvlen, iphdrlen, ipdatalen);
LOG(LOG_NOTICE, 0, "Packet from %s shorter (%u bytes) than hdr+data length (%u+%u).",
inetFmt(src, 1), recvlen, iphdrlen, ipdatalen);
else if ((ipdatalen < IGMP_MINLEN) || (igmp->igmp_type == IGMP_V3_MEMBERSHIP_REPORT && ipdatalen <= IGMPV3_MINLEN))
LOG(LOG_NOTICE, 0, "acceptIgmp: received IP data field too short (%u bytes) for IGMP, from %s.",
ipdatalen, inetFmt(src, 1));
LOG(LOG_NOTICE, 0, "IP data field too short (%u bytes) for IGMP, from %s.",
ipdatalen, inetFmt(src, 1));
else if (IfDp->conf->cksumVerify && cksum != inetChksum((uint16_t *)igmp, ipdatalen))
LOG(LOG_NOTICE, 0, "acceptIgmp: Received packet from: %s for: %s on: %s checksum incorrect.",
inetFmt(src, 1), inetFmt(dst, 2), IfDp->Name);
LOG(LOG_NOTICE, 0, "Packet from: %s for: %s on: %s checksum incorrect.",
inetFmt(src, 1), inetFmt(dst, 2), IfDp->Name);
else {
struct igmpv3_query *igmpv3 = (struct igmpv3_query *)(rcv_buf + iphdrlen);
struct igmpv3_report *igmpv3gr = (struct igmpv3_report *)(rcv_buf + iphdrlen);
Expand Down Expand Up @@ -272,12 +272,14 @@ void sendIgmp(struct IfDesc *IfDp, struct igmpv3_query *query) {
int len = 0;
struct sockaddr_in sdst;

if (IS_DISABLED(IfDp->state) || !IQUERY) {
if (IfDp->conf->tbl != mrt_tbl)
LOG(LOG_ERR, eABNRML, "Requested to send packet on table %d interface %s.", IfDp->conf->tbl, IfDp->Name);
else if (IS_DISABLED(IfDp->state) || !IQUERY) {
LOG(LOG_NOTICE, 0, "Not sending query for %s on %s interface %s.", inetFmt(query->igmp_group.s_addr, 1),
IS_DISABLED(IfDp->state) ? "disabled" : "non querier", IfDp->Name);
return;
} else if (query && (IfDp->querier.ver == 1 || (IfDp->querier.ver == 2 && query->igmp_nsrcs > 0))) {
LOG(LOG_NOTICE, 0, "Request to send group specific query on %s while in v%d mode, not sending.",
LOG(LOG_NOTICE, 0, "Not sending group and source specific query on %s while in v%d mode.",
IfDp->Name, IfDp->querier.ver);
return;
}
Expand Down Expand Up @@ -360,10 +362,8 @@ static void acceptMemberQuery(struct IfDesc *IfDp, uint32_t src, uint32_t dst, s
: ((getIgmpExp(IfDp->querier.qqi, 1) * IfDp->querier.qrv) * 10)
+ getIgmpExp(IfDp->querier.mrc, 1) / 2;
else if (ver == 2)
timeout = dst == allhosts_group ? (IfDp->conf->qry.interval * IfDp->conf->qry.robustness * 10)
+ igmpv3->igmp_code / 2
: ((IfDp->querier.qqi * IfDp->querier.qrv * 10) * 10)
+ IfDp->querier.mrc / 2;
timeout = dst == allhosts_group ? (IfDp->conf->qry.interval*IfDp->conf->qry.robustness*10) + igmpv3->igmp_code / 2
: ((IfDp->querier.qqi*IfDp->querier.qrv*10) * 10) + IfDp->querier.mrc / 2;
else
timeout = (100 * IfDp->conf->qry.robustness) + 5;
// Set timeout for other querier.
Expand Down
38 changes: 24 additions & 14 deletions src/igmpv3proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ static void igmpProxyRun(void);
volatile sig_atomic_t sighandled; // Should be as private as possible.
uint8_t sigstatus, logwarning;
struct timespec curtime, utcoff, starttime;
char *rcv_buf = NULL, *fileName, tS[32], tE[32], RUNPATH[] = RUN_PATHS, CFGPATH[] = CFG_PATHS;
char *rcv_buf = NULL, *fileName, tS[32], tE[32];
struct memstats memuse = { 0 }, memalloc = { 0 }, memfree = { 0 };
static struct pollfd pollFD[2] = { {-1, POLLIN, 0}, {-1, POLLIN, 0} };
const struct timespec nto = { 0, 0 };
Expand All @@ -64,7 +64,7 @@ struct chld chld = { 0 };
*/
int main(int ArgCn, char *ArgVc[]) {
int c = 0, i = 0, j = 0, tbl = 0;
char *opts[2] = { ArgVc[0], NULL }, cmd[20] = "", *path = NULL;
char *opts[2] = { ArgVc[0], NULL }, cmd[20] = "", *path;
struct stat st;
fileName = basename(ArgVc[0]);

Expand Down Expand Up @@ -154,7 +154,7 @@ int main(int ArgCn, char *ArgVc[]) {
fprintf(stderr, "%s: Must be started as root.\n", fileName);
exit(-1);
} else if (! (CONF->configFilePath = calloc(1, sizeof(CFG_PATHS) + strlen(ArgVc[optind - !(optind == ArgCn - 1)])))) {
// Freed by signalHandler()
// Freed by igmpProxyInit() or igmpProxyCleanUp()
fprintf(stderr, "%s. Out of Memory.\n", fileName);
exit(-1);
} else if (optind == ArgCn - 1 && !(stat(ArgVc[optind], &st) == 0 && (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)))) {
Expand All @@ -164,23 +164,28 @@ int main(int ArgCn, char *ArgVc[]) {
} else if (optind == ArgCn - 1) {
strcpy(CONF->configFilePath, ArgVc[optind]);
} else {
for (path = strtok(CFGPATH, " "); path && strcpy(CONF->configFilePath, path); path = strtok(NULL, " ")) {
fprintf(stderr, "%s: Looking for %s.conf config in default locations:", fileName, fileName);
for (i = 0, path = strtok(CFG_PATHS, " "); path && strcpy(CONF->configFilePath, path); path = strtok(NULL, " ")) {
// Search for config in default locations.
if (stat(strcat(strcat(CONF->configFilePath, fileName), ".conf"), &st) == 0)
break;
path[strlen(CONF->configFilePath) - 5] = '/';
path[strlen(CONF->configFilePath) - 4] = '\0';
fprintf(stderr, " %s", CONF->configFilePath);
CONF->configFilePath[strlen(CONF->configFilePath) - 5] = '/';
CONF->configFilePath[strlen(CONF->configFilePath) - 4] = '\0';
if (stat(strcat(strcat(CONF->configFilePath, fileName), ".conf"), &st) == 0)
break;
fprintf(stderr, " %s", CONF->configFilePath);
}
if (! path) {
fprintf(stderr, "%s. Config file path not found in %s.\n", fileName, CFG_PATHS);
if (path)
fprintf(stderr, "\n%s: Found %s\n", fileName, CONF->configFilePath);
else {
fprintf(stderr, "\n%s: None found\n", fileName);
exit(-1);
}
}

// Check for valid location to place socket and PID file.
for (path = strtok(RUNPATH, " "); path; path = strtok(NULL, " ")) {
for (path = strtok(RUN_PATHS, " "); path; path = strtok(NULL, " ")) {
if (stat(path, &st) >= 0) {
if (! (CONF->runPath = malloc(strlen(path) + strlen(fileName) + 8)))
fprintf(stderr, "Out of memory."); // Freed by igmpProxyCleanup()
Expand Down Expand Up @@ -424,11 +429,16 @@ static void igmpProxyInit(void) {
// Switch root if chroot is configured. The config file must be placed there.
if (CONF->chroot) {
// Truncate config and log file path to /.
char *b = basename(CONF->configFilePath);
strcpy(CONF->configFilePath, b);
char *b, *c;
if (! (b = basename(CONF->configFilePath)) || ! (c = calloc(1, strlen(b) + 1)) || ! strcpy(c, b))
LOG(LOG_ERR, eNOMEM, "Out of Memory.");
free(CONF->configFilePath); // Alloced by main()
CONF->configFilePath = c;
if (CONF->logFilePath) {
b = basename(CONF->logFilePath);
strcpy(CONF->logFilePath, b);
if (! (b = basename(CONF->logFilePath)) || ! (c = calloc(1, strlen(b) + 1)) || ! strcpy(c, b))
LOG(LOG_ERR, eNOMEM, "Out of Memory.");
free(CONF->logFilePath); // Alloced by loadConfig()
CONF->logFilePath = c;
}
// Link the root to the run directory and set runpath to /.
if (symlink(CONF->chroot, strcat(CONF->runPath, "root")) != 0 && errno != EEXIST)
Expand Down Expand Up @@ -495,7 +505,7 @@ void igmpProxyCleanUp(int code) {
remove(rFile);
sprintf(rFile, "%scli.sock", CONF->runPath);
remove(rFile);
if (rmdir(CONF->runPath) < 0)
if (! CONF->chroot && rmdir(CONF->runPath) < 0)
LOG(LOG_WARNING, errno, "Cannot remove run dir %s.", CONF->runPath);
}
if (!RESTART)
Expand Down
Loading

0 comments on commit 3c9b446

Please sign in to comment.