int recv_bcst_pkt ( SOCKET rsock, struct pkt *rpkt, unsigned int rsize, sockaddr_u *sas ) { sockaddr_u sender; int pkt_len = recv_bcst_data(rsock, (char *)rpkt, rsize, sas, &sender); if (pkt_len < 0) { return BROADCAST_FAILED; } pkt_len = process_pkt(rpkt, sas, pkt_len, MODE_BROADCAST, NULL, "recv_bcst_pkt"); return pkt_len; }
int recv_bcst_pkt ( SOCKET rsock, struct pkt *rpkt, sockaddr_u *sas ) { sockaddr_u sender; register int a; int is_authentic, has_mac = 0, orig_pkt_len; char *rdata = emalloc(sizeof(char) * 256); int pkt_len = recv_bcst_data(rsock, rdata, 256, sas, &sender); if (pkt_len < 0) { free(rdata); return BROADCAST_FAILED; } /* No MAC, no authentication */ if (LEN_PKT_NOMAC == pkt_len) has_mac = 0; /* If there's more than just the NTP packet it should be a MAC */ else if(pkt_len > LEN_PKT_NOMAC) has_mac = pkt_len - LEN_PKT_NOMAC; else if(ENABLED_OPT(NORMALVERBOSE)) { printf("sntp recv_bcst_pkt: Funny packet length: %i. Discarding package.\n", pkt_len); free(rdata); return PACKET_UNUSEABLE; } /* Packet too big */ if(pkt_len > LEN_PKT_NOMAC + MAX_MAC_LEN) { if(ENABLED_OPT(NORMALVERBOSE)) printf("sntp recv_bcst_pkt: Received packet is too big (%i bytes), trying again to get a useFable packet\n", pkt_len); free(rdata); return PACKET_UNUSEABLE; } orig_pkt_len = pkt_len; pkt_len = min(pkt_len, sizeof(struct pkt)); /* Let's copy the received data to the packet structure */ for (a = 0; a < pkt_len; a++) if (a < orig_pkt_len) ((char *)rpkt)[a] = rdata[a]; else ((char *)rpkt)[a] = 0; free(rdata); /* MAC could be useable for us */ if (has_mac) { /* Two more things that the MAC must conform to */ if (has_mac > MAX_MAC_LEN || has_mac % 4 != 0) { is_authentic = 0; /* Or should we discard this packet? */ } else { if (MAX_MAC_LEN == has_mac) { struct key *pkt_key = NULL; /* Look for the key used by the server in the specified keyfile * and if existent, fetch it or else leave the pointer untouched */ get_key(rpkt->mac[0], &pkt_key); /* Seems like we've got a key with matching keyid */ if (pkt_key != NULL) { /* Generate a md5sum of the packet with the key from our keyfile * and compare those md5sums */ if (!auth_md5((char *) rpkt, has_mac, pkt_key)) { if (ENABLED_OPT(AUTHENTICATION)) { /* We want a authenticated packet */ if (ENABLED_OPT(NORMALVERBOSE)) { char *hostname = ss_to_str(sas); printf("sntp recv_bcst_pkt: Broadcast packet received from %s is not authentic. Will discard this packet.\n", hostname); free(hostname); } return SERVER_AUTH_FAIL; } else { /* We don't know if the user wanted authentication so let's * use it anyways */ if (ENABLED_OPT(NORMALVERBOSE)) { char *hostname = ss_to_str(sas); printf("sntp recv_bcst_pkt: Broadcast packet received from %s is not authentic. Authentication not enforced.\n", hostname); free(hostname); } is_authentic = 0; } } else { /* Yay! Things worked out! */ if (ENABLED_OPT(NORMALVERBOSE)) { char *hostname = ss_to_str(sas); printf("sntp recv_bcst_pkt: Broadcast packet received from %s successfully authenticated using key id %i.\n", hostname, rpkt->mac[0]); free(hostname); } is_authentic = 1; } } } } } /* Check for server's ntp version */ if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION || PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) { if (ENABLED_OPT(NORMALVERBOSE)) printf("sntp recv_bcst_pkt: Packet shows wrong version (%i)\n", PKT_VERSION(rpkt->li_vn_mode)); return SERVER_UNUSEABLE; } /* We want a server to sync with */ if (PKT_MODE(rpkt->li_vn_mode) != MODE_BROADCAST && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) { if (ENABLED_OPT(NORMALVERBOSE)) printf("sntp recv_bcst_pkt: mode %d stratum %i\n", PKT_MODE(rpkt->li_vn_mode), rpkt->stratum); return SERVER_UNUSEABLE; } if (STRATUM_PKT_UNSPEC == rpkt->stratum) { char *ref_char; if (ENABLED_OPT(NORMALVERBOSE)) printf("sntp recv_bcst_pkt: Stratum unspecified, going to check for KOD (stratum: %i)\n", rpkt->stratum); ref_char = (char *) &rpkt->refid; /* If it's a KOD packet we'll just use the KOD information */ if (ref_char[0] != 'X') { if (strncmp(ref_char, "DENY", 4)) return KOD_DEMOBILIZE; if (strncmp(ref_char, "RSTR", 4)) return KOD_DEMOBILIZE; if (strncmp(ref_char, "RATE", 4)) return KOD_RATE; /* There are other interesting kiss codes which might be interesting for authentication */ } } /* If the server is not synced it's not really useable for us */ if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) { if (ENABLED_OPT(NORMALVERBOSE)) printf("recv_bcst_pkt: Server not in sync, skipping this server\n"); return SERVER_UNUSEABLE; } return pkt_len; }