int show_session_msg(struct imsg *imsg) { struct rsession *con; char a[128], b[128]; struct timeval tv_now; switch (imsg->hdr.type) { case IMSG_CTL_SESSION: con = imsg->data; (void)print_host(&con->se_in.ss, a, sizeof(a)); (void)print_host(&con->se_out.ss, b, sizeof(b)); printf("session %u:%u %s:%u -> %s:%u\t%s\n", imsg->hdr.peerid, con->se_id, a, ntohs(con->se_in.port), b, ntohs(con->se_out.port), con->se_done ? "DONE" : "RUNNING"); getmonotime(&tv_now); print_time(&tv_now, &con->se_tv_start, a, sizeof(a)); print_time(&tv_now, &con->se_tv_last, b, sizeof(b)); printf("\tage %s, idle %s, relay %u, pid %u", a, b, con->se_relayid, con->se_pid); if (con->se_mark) printf(", mark %u", con->se_mark); printf("\n"); break; case IMSG_CTL_END: return (1); default: errx(1, "wrong message in session: %u", imsg->hdr.type); break; } return (0); }
static void message(const char *profile, const char *fmt, ...) { static char *previous = 0; static struct timeval zen; static const struct timeval tmo = { 0, 100 * 1000 }; struct timeval now, dif; int gap = 0; getmonotime(&now); timersub(&now, &zen, &dif); if( timercmp(&tmo, &dif, <) ) { zen = now; gap = 1; } if( !xstrsame(previous, profile) ) { xstrset(&previous, profile); gap = 1; } if( gap ) printf("\n"); va_list va; va_start(va, fmt); vprintf(fmt, va); va_end(va); }
static void timeout_init(struct timeval *tmo, int msec) { struct timeval now; getmonotime(&now,0); tmo->tv_sec = (msec / 1000); tmo->tv_usec = (msec % 1000) * 1000; timeradd(tmo, &now, tmo); }
int relay_dns_request(struct rsession *con) { struct relay *rlay = con->se_relay; struct relay_dns_priv *priv = con->se_priv; u_int8_t *buf = EVBUFFER_DATA(con->se_out.output); size_t len = EVBUFFER_LENGTH(con->se_out.output); struct relay_dnshdr *hdr; socklen_t slen; if (buf == NULL || priv == NULL || len < 1) return (-1); if (debug) relay_dns_log(con, buf, len); getmonotime(&con->se_tv_start); if (!TAILQ_EMPTY(&rlay->rl_tables)) { if (relay_from_table(con) != 0) return (-1); } else if (con->se_out.ss.ss_family == AF_UNSPEC) { bcopy(&rlay->rl_conf.dstss, &con->se_out.ss, sizeof(con->se_out.ss)); con->se_out.port = rlay->rl_conf.dstport; } if ((con->se_out.s = relay_udp_socket(&con->se_out.ss, con->se_out.port, rlay->rl_proto)) == -1) return (-1); slen = con->se_out.ss.ss_len; hdr = (struct relay_dnshdr *)buf; hdr->dns_id = htons(priv->dp_inkey); retry: if (sendto(con->se_out.s, buf, len, 0, (struct sockaddr *)&con->se_out.ss, slen) == -1) { if (con->se_retry) { con->se_retry--; log_debug("%s: session %d: " "forward failed: %s, %s", __func__, con->se_id, strerror(errno), con->se_retry ? "next retry" : "last retry"); goto retry; } log_debug("%s: session %d: forward failed: %s", __func__, con->se_id, strerror(errno)); return (-1); } event_again(&con->se_ev, con->se_out.s, EV_TIMEOUT|EV_READ, relay_udp_response, &con->se_tv_start, &env->sc_timeout, con); return (0); }
static void mysleep(int msec) { //printf("SLEEP %d ms\n", msec); struct timeval t1,t2; getmonotime(&t1,0); if( dbus_connection_read_write(connection, msec) ) { do { puts("dbus dispatch"); } while( dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS ); } getmonotime(&t2,0); timersub(&t2,&t1,&t1); printf("SLEPT %.3f / %.3f s\n", t1.tv_sec + t1.tv_usec * 1e-6, msec * 1e-3); }
static int timeout_left(const struct timeval *tmo) { int res = 0; struct timeval now; getmonotime(&now,0); if( timercmp(&now, tmo, <) ) { timersub(tmo,&now,&now); res = now.tv_sec * 1000 + now.tv_usec / 1000; } return res; }
void show_status_msg(struct imsg *imsg) { struct ctl_show_status *cstatus; double clock_offset; struct timeval tv; if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(struct ctl_show_status)) fatalx("invalid IMSG_CTL_SHOW_STATUS received"); cstatus = (struct ctl_show_status *)imsg->data; if (cstatus->peercnt > 0) printf("%d/%d peers valid, ", cstatus->valid_peers, cstatus->peercnt); if (cstatus->sensorcnt > 0) printf("%d/%d sensors valid, ", cstatus->valid_sensors, cstatus->sensorcnt); if (cstatus->constraint_median) { tv.tv_sec = cstatus->constraint_median + (getmonotime() - cstatus->constraint_last); tv.tv_usec = 0; d_to_tv(gettime_from_timeval(&tv) - gettime(), &tv); printf("constraint offset %llds", (long long)tv.tv_sec); if (cstatus->constraint_errors) printf(" (%d errors)", cstatus->constraint_errors); printf(", "); } if (cstatus->peercnt + cstatus->sensorcnt == 0) printf("no peers and no sensors configured\n"); if (cstatus->synced == 1) printf("clock synced, stratum %u\n", cstatus->stratum); else { printf("clock unsynced"); clock_offset = cstatus->clock_offset < 0 ? -1.0 * cstatus->clock_offset : cstatus->clock_offset; if (clock_offset > 5e-7) printf(", clock offset is %.3fms\n", cstatus->clock_offset); else printf("\n"); } }
void set_deadline(struct ntp_peer *p, time_t t) { p->deadline = getmonotime() + t; p->next = 0; }
int client_dispatch(struct ntp_peer *p, u_int8_t settime) { struct ntp_msg msg; struct msghdr somsg; struct iovec iov[1]; struct timeval tv; char buf[NTP_MSGSIZE]; union { struct cmsghdr hdr; char buf[CMSG_SPACE(sizeof(tv))]; } cmsgbuf; struct cmsghdr *cmsg; ssize_t size; double T1, T2, T3, T4; time_t interval; bzero(&somsg, sizeof(somsg)); iov[0].iov_base = buf; iov[0].iov_len = sizeof(buf); somsg.msg_iov = iov; somsg.msg_iovlen = 1; somsg.msg_control = cmsgbuf.buf; somsg.msg_controllen = sizeof(cmsgbuf.buf); T4 = getoffset(); if ((size = recvmsg(p->query->fd, &somsg, 0)) == -1) { if (errno == EHOSTUNREACH || errno == EHOSTDOWN || errno == ENETUNREACH || errno == ENETDOWN || errno == ECONNREFUSED || errno == EADDRNOTAVAIL || errno == ENOPROTOOPT || errno == ENOENT) { client_log_error(p, "recvmsg", errno); set_next(p, error_interval()); return (0); } else fatal("recvfrom"); } if (somsg.msg_flags & MSG_TRUNC) { client_log_error(p, "recvmsg packet", EMSGSIZE); set_next(p, error_interval()); return (0); } if (somsg.msg_flags & MSG_CTRUNC) { client_log_error(p, "recvmsg control data", E2BIG); set_next(p, error_interval()); return (0); } #ifdef HAVE_RTABLE if (p->rtable != -1 && setsockopt(p->query->fd, SOL_SOCKET, SO_RTABLE, &p->rtable, sizeof(p->rtable)) == -1) fatal("client_dispatch setsockopt SO_RTABLE"); #endif for (cmsg = CMSG_FIRSTHDR(&somsg); cmsg != NULL; cmsg = CMSG_NXTHDR(&somsg, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMP) { memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv)); T4 += tv.tv_sec + JAN_1970 + 1.0e-6 * tv.tv_usec; break; } } if (T4 < JAN_1970) { client_log_error(p, "recvmsg control format", EBADF); set_next(p, error_interval()); return (0); } ntp_getmsg((struct sockaddr *)&p->addr->ss, buf, size, &msg); if (msg.orgtime.int_partl != p->query->msg.xmttime.int_partl || msg.orgtime.fractionl != p->query->msg.xmttime.fractionl) return (0); if ((msg.status & LI_ALARM) == LI_ALARM || msg.stratum == 0 || msg.stratum > NTP_MAXSTRATUM) { char s[16]; if ((msg.status & LI_ALARM) == LI_ALARM) { strlcpy(s, "alarm", sizeof(s)); } else if (msg.stratum == 0) { /* Kiss-o'-Death (KoD) packet */ strlcpy(s, "KoD", sizeof(s)); } else if (msg.stratum > NTP_MAXSTRATUM) { snprintf(s, sizeof(s), "stratum %d", msg.stratum); } interval = error_interval(); set_next(p, interval); log_info("reply from %s: not synced (%s), next query %llds", log_sockaddr((struct sockaddr *)&p->addr->ss), s, (long long)interval); return (0); } /* * From RFC 2030 (with a correction to the delay math): * * Timestamp Name ID When Generated * ------------------------------------------------------------ * Originate Timestamp T1 time request sent by client * Receive Timestamp T2 time request received by server * Transmit Timestamp T3 time reply sent by server * Destination Timestamp T4 time reply received by client * * The roundtrip delay d and local clock offset t are defined as * * d = (T4 - T1) - (T3 - T2) t = ((T2 - T1) + (T3 - T4)) / 2. */ T1 = p->query->xmttime; T2 = lfp_to_d(msg.rectime); T3 = lfp_to_d(msg.xmttime); /* * XXX workaround: time_t / tv_sec must never wrap. * around 2020 we will need a solution (64bit time_t / tv_sec). * consider every answer with a timestamp beyond january 2030 bogus. */ if (T2 > JAN_2030 || T3 > JAN_2030) { set_next(p, error_interval()); return (0); } p->reply[p->shift].offset = ((T2 - T1) + (T3 - T4)) / 2; p->reply[p->shift].delay = (T4 - T1) - (T3 - T2); p->reply[p->shift].status.stratum = msg.stratum; if (p->reply[p->shift].delay < 0) { interval = error_interval(); set_next(p, interval); log_info("reply from %s: negative delay %fs, " "next query %llds", log_sockaddr((struct sockaddr *)&p->addr->ss), p->reply[p->shift].delay, (long long)interval); return (0); } p->reply[p->shift].error = (T2 - T1) - (T3 - T4); p->reply[p->shift].rcvd = getmonotime(); p->reply[p->shift].good = 1; p->reply[p->shift].status.leap = (msg.status & LIMASK); p->reply[p->shift].status.precision = msg.precision; p->reply[p->shift].status.rootdelay = sfp_to_d(msg.rootdelay); p->reply[p->shift].status.rootdispersion = sfp_to_d(msg.dispersion); p->reply[p->shift].status.refid = msg.refid; p->reply[p->shift].status.reftime = lfp_to_d(msg.reftime); p->reply[p->shift].status.poll = msg.ppoll; if (p->addr->ss.ss_family == AF_INET) { p->reply[p->shift].status.send_refid = ((struct sockaddr_in *)&p->addr->ss)->sin_addr.s_addr; } else if (p->addr->ss.ss_family == AF_INET6) { MD5_CTX context; u_int8_t digest[MD5_DIGEST_LENGTH]; MD5_Init(&context); MD5_Update(&context, ((struct sockaddr_in6 *)&p->addr->ss)-> sin6_addr.s6_addr, sizeof(struct in6_addr)); MD5_Final(digest, &context); memcpy((char *)&p->reply[p->shift].status.send_refid, digest, sizeof(u_int32_t)); } else p->reply[p->shift].status.send_refid = msg.xmttime.fractionl; if (p->trustlevel < TRUSTLEVEL_PATHETIC) interval = scale_interval(INTERVAL_QUERY_PATHETIC); else if (p->trustlevel < TRUSTLEVEL_AGGRESSIVE) interval = scale_interval(INTERVAL_QUERY_AGGRESSIVE); else interval = scale_interval(INTERVAL_QUERY_NORMAL); set_next(p, interval); p->state = STATE_REPLY_RECEIVED; /* every received reply which we do not discard increases trust */ if (p->trustlevel < TRUSTLEVEL_MAX) { if (p->trustlevel < TRUSTLEVEL_BADPEER && p->trustlevel + 1 >= TRUSTLEVEL_BADPEER) log_info("peer %s now valid", log_sockaddr((struct sockaddr *)&p->addr->ss)); p->trustlevel++; } log_debug("reply from %s: offset %f delay %f, " "next query %llds %s", log_sockaddr((struct sockaddr *)&p->addr->ss), p->reply[p->shift].offset, p->reply[p->shift].delay, (long long)interval, print_rtable(p->rtable)); client_update(p); if (settime) priv_settime(p->reply[p->shift].offset); if (++p->shift >= OFFSET_ARRAY_SIZE) p->shift = 0; return (0); }
void relay_udp_server(int fd, short sig, void *arg) { struct relay *rlay = arg; struct protocol *proto = rlay->rl_proto; struct rsession *con = NULL; struct ctl_natlook *cnl = NULL; socklen_t slen; struct timeval tv; struct sockaddr_storage ss; u_int8_t buf[IBUF_READ_SIZE]; void *priv = NULL; ssize_t len; if (relay_sessions >= RELAY_MAX_SESSIONS || rlay->rl_conf.flags & F_DISABLE) return; slen = sizeof(ss); if ((len = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr*)&ss, &slen)) < 1) return; if (proto->validate != NULL && (priv = (*proto->validate)(NULL, rlay, &ss, buf, len)) == NULL) return; if ((con = calloc(1, sizeof(*con))) == NULL) { free(priv); return; } /* * Replace the DNS request Id with a random Id. */ con->se_priv = priv; con->se_in.s = -1; con->se_out.s = -1; con->se_in.dst = &con->se_out; con->se_out.dst = &con->se_in; con->se_in.con = con; con->se_out.con = con; con->se_relay = rlay; con->se_id = ++relay_conid; con->se_in.dir = RELAY_DIR_REQUEST; con->se_out.dir = RELAY_DIR_RESPONSE; con->se_retry = rlay->rl_conf.dstretry; con->se_out.port = rlay->rl_conf.dstport; switch (ss.ss_family) { case AF_INET: con->se_in.port = ((struct sockaddr_in *)&ss)->sin_port; break; case AF_INET6: con->se_in.port = ((struct sockaddr_in6 *)&ss)->sin6_port; break; } bcopy(&ss, &con->se_in.ss, sizeof(con->se_in.ss)); getmonotime(&con->se_tv_start); bcopy(&con->se_tv_start, &con->se_tv_last, sizeof(con->se_tv_last)); relay_sessions++; SPLAY_INSERT(session_tree, &rlay->rl_sessions, con); /* Increment the per-relay session counter */ rlay->rl_stats[proc_id].last++; /* Pre-allocate output buffer */ con->se_out.output = evbuffer_new(); if (con->se_out.output == NULL) { relay_close(con, "failed to allocate output buffer"); return; } /* Pre-allocate log buffer */ con->se_log = evbuffer_new(); if (con->se_log == NULL) { relay_close(con, "failed to allocate log buffer"); return; } if (rlay->rl_conf.flags & F_NATLOOK) { if ((cnl = calloc(1, sizeof(*cnl))) == NULL) { relay_close(con, "failed to allocate natlookup"); return; } } /* Save the received data */ if (evbuffer_add(con->se_out.output, buf, len) == -1) { relay_close(con, "failed to store buffer"); if (cnl != NULL) free(cnl); return; } if (cnl != NULL) { con->se_cnl = cnl; bzero(cnl, sizeof(*cnl)); cnl->in = -1; cnl->id = con->se_id; cnl->proc = proc_id; cnl->proto = IPPROTO_UDP; bcopy(&con->se_in.ss, &cnl->src, sizeof(cnl->src)); bcopy(&rlay->rl_conf.ss, &cnl->dst, sizeof(cnl->dst)); proc_compose_imsg(env->sc_ps, PROC_PFE, -1, IMSG_NATLOOK, -1, cnl, sizeof(*cnl)); /* Schedule timeout */ evtimer_set(&con->se_ev, relay_natlook, con); bcopy(&rlay->rl_conf.timeout, &tv, sizeof(tv)); evtimer_add(&con->se_ev, &tv); return; } relay_session(con); }