void udp_socks_register(struct udpcommon *uc, struct udpsocks *socks);
void udp_socks_deregister(struct udpcommon *uc, struct udpsocks *socks);
+void udp_socks_childpersist(struct udpcommon *uc, struct udpsocks *socks);
#define UDP_APPLY_STANDARD(st,uc,desc) \
(uc)->use_proxy=False; \
}
}
+static void polypath_phase_childpersist(void *sst, uint32_t newphase)
+{
+ struct polypath *st=sst;
+ struct interf *interf;
+
+ LIST_FOREACH(interf,&st->interfs,entry)
+ udp_socks_childpersist(&st->uc,&interf->socks);
+}
+
#undef BAD
#undef BADE
add_hook(PHASE_RUN, polypath_phase_startmonitor,st);
add_hook(PHASE_SHUTDOWN, polypath_phase_shutdown, st);
+ add_hook(PHASE_CHILDPERSIST,polypath_phase_childpersist,st);
return new_closure(&cc->cl);
}
sigprocmask(SIG_SETMASK,&emptyset,NULL);
}
+void childpersist_closefd_hook(void *fd_vp, uint32_t newphase)
+{
+ int *fd_p=fd_vp;
+ int fd=*fd_p;
+ if (fd<0) return;
+ *fd_p=-1;
+ setnonblock(fd); /* in case close() might block */
+ close(fd); /* discard errors - we don't care, in the child */
+}
+
static void signal_handler(int signum)
{
int saved_errno;
/* Must be called before exec in every child made after
start_signal_handling. Safe to call in earlier children too. */
+void childpersist_closefd_hook(void *fd_p, uint32_t newphase);
+/* Convenience hook function for use with add_hook PHASE_CHILDPERSIST.
+ With `int fd' in your state struct, pass fd_p=&fd. The hook checks
+ whether fd>=0, so you can use it for an fd which is only sometimes
+ open. This function will set fd to -1, so it is idempotent. */
+
/***** CONFIGURATION support *****/
extern bool_t just_check_config; /* If True then we're going to exit after
PHASE_DROPPRIV, /* Last chance for privileged operations */
PHASE_RUN,
PHASE_SHUTDOWN, /* About to die; delete key material, etc. */
+ PHASE_CHILDPERSIST, /* Forked long-term child: close fds, etc. */
/* Keep this last: */
NR_PHASES,
};
+/* Each module should, in its CHILDPERSIST hooks, close all fds which
+ constitute ownership of important operating system resources, or
+ which are used for IPC with other processes who want to get the
+ usual disconnection effects if the main secnet process dies.
+ CHILDPERSIST hooks are not run if the child is going to exec;
+ so fds such as described above should be CLOEXEC too. */
+
typedef void hook_fn(void *self, uint32_t newphase);
bool_t add_hook(uint32_t phase, hook_fn *f, void *state);
bool_t remove_hook(uint32_t phase, hook_fn *f, void *state);
send_msg7(st,"shutting down");
}
+static void site_childpersist_clearkeys(void *sst, uint32_t newphase)
+{
+ struct site *st=sst;
+ dispose_transform(&st->current.transform);
+ dispose_transform(&st->auxiliary_key.transform);
+ dispose_transform(&st->new_transform);
+ /* Not much point overwiting the signing key, since we loaded it
+ from disk, and it is only valid prospectively if at all,
+ anyway. */
+ /* XXX it would be best to overwrite the DH state, because that
+ _is_ relevant to forward secrecy. However we have no
+ convenient interface for doing that and in practice gmp has
+ probably dribbled droppings all over the malloc arena. A good
+ way to fix this would be to have a privsep child for asymmetric
+ crypto operations, but that's a task for another day. */
+}
+
static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
list_t *args)
{
enter_state_stop(st);
add_hook(PHASE_SHUTDOWN,site_phase_hook,st);
+ add_hook(PHASE_CHILDPERSIST,site_childpersist_clearkeys,st);
return new_closure(&st->cl);
}
}
setnonblock(st->txfd);
setnonblock(st->rxfd);
+
+ add_hook(PHASE_CHILDPERSIST,childpersist_closefd_hook,&st->txfd);
+ add_hook(PHASE_CHILDPERSIST,childpersist_closefd_hook,&st->rxfd);
}
static void userv_kill_userv(struct userv *st)
tun_set_route(st,r);
}
+ add_hook(PHASE_CHILDPERSIST,childpersist_closefd_hook,&st->fd);
+
/* Register for poll() */
register_for_poll(st, tun_beforepoll, tun_afterpoll, st->nl.name);
}
deregister_for_poll(socks->interest);
}
+void udp_socks_childpersist(struct udpcommon *uc, struct udpsocks *socks)
+{
+ int i;
+ for (i=0; i<socks->n_socks; i++)
+ udp_destroy_socket(uc,&socks->socks[i]);
+}
+
+static void udp_childpersist_hook(void *sst, uint32_t new_phase)
+{
+ struct udp *st=sst;
+ udp_socks_childpersist(&st->uc,&st->socks);
+}
+
static void udp_phase_hook(void *sst, uint32_t new_phase)
{
struct udp *st=sst;
udp_make_socket(uc,&socks->socks[i],M_FATAL);
udp_socks_register(uc,socks);
+
+ add_hook(PHASE_CHILDPERSIST,udp_childpersist_hook,st);
}
static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context,
"PHASE_GETRESOURCES",
"PHASE_DROPPRIV",
"PHASE_RUN",
- "PHASE_SHUTDOWN"
+ "PHASE_SHUTDOWN",
+ "PHASE_CHILDPERSIST"
};
void enter_phase(uint32_t new_phase)