/** * Sends out a data packet. All headers should be populated except blsize */ int send_data(const struct finfo_t *finfo, unsigned char *packet, int datalen, unsigned char *encpacket) { struct uftp_h *header; struct fileseg_h *fileseg; int payloadlen; unsigned char *outpacket; header = (struct uftp_h *)packet; fileseg = (struct fileseg_h *)(packet + sizeof(struct uftp_h)); payloadlen = sizeof(struct fileseg_h) + datalen; if (keytype != KEY_NONE) { if (!encrypt_and_sign(packet, &encpacket, payloadlen, mtu, keytype, groupkey, groupsalt, ivlen, hashtype, grouphmackey, hmaclen, sigtype, privkey, rsalen)) { log0(0, 0, "Error encrypting FILESEG"); return 0; } outpacket = encpacket; payloadlen = ntohs(((struct uftp_h *)outpacket)->blsize); } else { outpacket = packet; header->blsize = htons(payloadlen); } if (nb_sendto(sock, outpacket, payloadlen + sizeof(struct uftp_h), 0, (struct sockaddr *)&receive_dest, sizeof(receive_dest)) == SOCKET_ERROR) { sockerror(0, 0, "Error sending FILESEG"); return 0; } return 1; }
/** * Sends a KEYINFO_ACK in response to a KEYINFO */ void send_keyinfo_ack(struct group_list_t *group) { unsigned char *buf, *encrypted; struct uftp_h *header; struct keyinfoack_h *keyinfo_ack; unsigned char *verifydata, *verify_hash, *verify_val; unsigned int payloadlen, hashlen; int verifylen, enclen, len; buf = safe_calloc(MAXMTU, 1); header = (struct uftp_h *)buf; keyinfo_ack = (struct keyinfoack_h *)(buf + sizeof(struct uftp_h)); set_uftp_header(header, KEYINFO_ACK, group); keyinfo_ack->func = KEYINFO_ACK; keyinfo_ack->hlen = sizeof(struct keyinfoack_h) / 4; verifydata = build_verify_data(group, &verifylen); if (!verifydata) { glog0(group, "Error getting verify data"); send_abort(group, "Error getting verify data"); free(buf); return; } verify_hash = safe_calloc(group->hmaclen, 1); verify_val = safe_calloc(VERIFY_LEN + group->hmaclen, 1); hash(group->hashtype, verifydata, verifylen, verify_hash, &hashlen); PRF(group->hashtype, VERIFY_LEN, group->groupmaster, sizeof(group->groupmaster), "client finished", verify_hash, hashlen, verify_val, &len); memcpy(keyinfo_ack->verify_data, verify_val, VERIFY_LEN); free(verifydata); free(verify_hash); free(verify_val); payloadlen = sizeof(struct keyinfoack_h); encrypted = NULL; if (!encrypt_and_sign(buf, &encrypted, payloadlen, &enclen, group->keytype, group->groupkey, group->groupsalt, &group->ivctr, group->ivlen, group->hashtype, group->grouphmackey, group->hmaclen,group->sigtype, group->keyextype, group->client_privkey,group->client_privkeylen)) { glog0(group, "Error encrypting KEYINFO_ACK"); free(buf); return; } payloadlen = enclen + sizeof(struct uftp_h); if (nb_sendto(listener, encrypted, payloadlen, 0, (struct sockaddr *)&(group->replyaddr), family_len(group->replyaddr)) == SOCKET_ERROR) { gsockerror(group, "Error sending KEYINFO_ACK"); } else { glog2(group, "KEYINFO_ACK sent"); } free(encrypted); free(buf); }
/** * Sends back a CC_ACK message for congestion control feedback */ void send_cc_ack(struct group_list_t *group) { unsigned char *buf, *encrypted, *outpacket; struct uftp_h *header; struct cc_ack_h *cc_ack; struct tfmcc_ack_info_he *tfmcc; int payloadlen, enclen; buf = safe_calloc(MAXMTU, 1); header = (struct uftp_h *)buf; cc_ack = (struct cc_ack_h *)(buf + sizeof(struct uftp_h)); tfmcc = (struct tfmcc_ack_info_he *)((unsigned char *)cc_ack + sizeof(struct cc_ack_h)); set_uftp_header(header, CC_ACK, group); cc_ack->func = CC_ACK; cc_ack->hlen = (sizeof(struct cc_ack_h) + sizeof(struct tfmcc_ack_info_he)) / 4; set_tfmcc_ack_info(group, tfmcc); payloadlen = cc_ack->hlen * 4; if ((group->phase != PHASE_REGISTERED) && (group->keytype != KEY_NONE)) { encrypted = NULL; if (!encrypt_and_sign(buf, &encrypted, payloadlen, &enclen, group->keytype, group->groupkey, group->groupsalt,&group->ivctr, group->ivlen, group->hashtype, group->grouphmackey, group->hmaclen, group->sigtype, group->keyextype, group->client_privkey, group->client_privkeylen)) { glog0(group, "Error encrypting CC_ACK"); free(buf); return; } outpacket = encrypted; payloadlen = enclen; } else { encrypted = NULL; outpacket = buf; } payloadlen += sizeof(struct uftp_h); if (nb_sendto(listener, outpacket, payloadlen, 0, (struct sockaddr *)&group->replyaddr, family_len(group->replyaddr)) == SOCKET_ERROR) { gsockerror(group, "Error sending CC_ACK"); } else { glog2(group, "CC_ACK sent"); } set_timeout(group, 0); group->cc_time.tv_sec = 0; group->cc_time.tv_usec = 0; free(buf); }
/** * Sends an ABORT message to one or more clients */ void send_abort(const struct finfo_t *finfo, const char *message, const struct sockaddr_in *destaddr, const struct in_addr *dest, int encrypt) { unsigned char *buf, *encrypted, *outpacket; struct uftp_h *header; struct abort_h *abort; int payloadlen; buf = calloc(mtu, 1); if (buf == NULL) { syserror(0, 0, "calloc failed!"); exit(1); } header = (struct uftp_h *)buf; abort = (struct abort_h *)(buf + sizeof(struct uftp_h)); set_uftp_header(header, ABORT, finfo, destaddr); abort->func = ABORT; if (dest) { abort->host = dest->s_addr; } strncpy(abort->message, message, sizeof(abort->message) - 1); payloadlen = sizeof(struct abort_h); if (encrypt) { encrypted = NULL; if (!encrypt_and_sign(buf, &encrypted, payloadlen, mtu, keytype, groupkey, groupsalt, ivlen, hashtype, grouphmackey, hmaclen, sigtype, privkey, rsalen)) { log0(0, 0, "Error encrypting ABORT"); free(buf); return; } outpacket = encrypted; payloadlen = ntohs(((struct uftp_h *)outpacket)->blsize); } else { encrypted = NULL; outpacket = buf; header->blsize = htons(payloadlen); } if (nb_sendto(sock, outpacket, payloadlen + sizeof(struct uftp_h), 0, (struct sockaddr *)destaddr, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { sockerror(0, 0, "Error sending ABORT"); } free(buf); free(encrypted); }
/** * Sends an ABORT message to a server */ void send_abort(struct group_list_t *group, const char *message) { unsigned char *buf, *encrypted, *outpacket; struct uftp_h *header; struct abort_h *abort_hdr; int payloadlen, enclen; buf = safe_calloc(MAXMTU, 1); header = (struct uftp_h *)buf; abort_hdr = (struct abort_h *)(buf + sizeof(struct uftp_h)); set_uftp_header(header, ABORT, group); abort_hdr->func = ABORT; abort_hdr->hlen = sizeof(struct abort_h) / 4; abort_hdr->host = 0; strncpy(abort_hdr->message, message, sizeof(abort_hdr->message) - 1); payloadlen = sizeof(struct abort_h); if ((group->phase != PHASE_REGISTERED) && (group->keytype != KEY_NONE)) { encrypted = NULL; if (!encrypt_and_sign(buf, &encrypted, payloadlen, &enclen, group->keytype, group->groupkey, group->groupsalt,&group->ivctr, group->ivlen, group->hashtype, group->grouphmackey, group->hmaclen, group->sigtype, group->keyextype, group->client_privkey, group->client_privkeylen)) { glog0(group, "Error encrypting ABORT"); free(buf); return; } outpacket = encrypted; payloadlen = enclen; } else { encrypted = NULL; outpacket = buf; } payloadlen += sizeof(struct uftp_h); if (nb_sendto(listener, outpacket, payloadlen, 0, (struct sockaddr *)&group->replyaddr, family_len(group->replyaddr)) == SOCKET_ERROR) { gsockerror(group, "Error sending ABORT"); } flush_disk_cache(group); file_cleanup(group, 1); free(buf); free(encrypted); }
/** * Sends back a COMPLETE message in response to a DONE or FILEINFO */ void send_complete(struct group_list_t *group, int set_freespace) { unsigned char *buf, *encrypted, *outpacket; struct uftp_h *header; struct complete_h *complete; struct freespace_info_he *freespace; int payloadlen, enclen; struct timeval tv; gettimeofday(&tv, NULL); if ((group->phase == PHASE_COMPLETE) && (cmptimestamp(tv, group->expire_time) >= 0)) { glog1(group, "Completion unconfirmed by server"); move_files(group); file_cleanup(group, 0); return; } buf = safe_calloc(MAXMTU, 1); header = (struct uftp_h *)buf; complete = (struct complete_h *)(buf + sizeof(struct uftp_h)); freespace = (struct freespace_info_he *)((unsigned char *)complete + sizeof(struct complete_h)); set_uftp_header(header, COMPLETE, group); complete->func = COMPLETE; if (set_freespace) { complete->hlen = (sizeof(struct complete_h) + sizeof(struct freespace_info_he)) / 4; } else { complete->hlen = sizeof(struct complete_h) / 4; } complete->status = group->fileinfo.comp_status; complete->file_id = htons(group->file_id); if (set_freespace) { set_freespace_info(group, freespace); } payloadlen = complete->hlen * 4; if ((group->phase != PHASE_REGISTERED) && (group->keytype != KEY_NONE)) { encrypted = NULL; if (!encrypt_and_sign(buf, &encrypted, payloadlen, &enclen, group->keytype, group->groupkey, group->groupsalt,&group->ivctr, group->ivlen, group->hashtype, group->grouphmackey, group->hmaclen, group->sigtype, group->keyextype, group->client_privkey, group->client_privkeylen)) { glog0(group, "Error encrypting COMPLETE"); free(buf); return; } outpacket = encrypted; payloadlen = enclen; } else { encrypted = NULL; outpacket = buf; } payloadlen += sizeof(struct uftp_h); if (nb_sendto(listener, outpacket, payloadlen, 0, (struct sockaddr *)&group->replyaddr, family_len(group->replyaddr)) == SOCKET_ERROR) { gsockerror(group, "Error sending COMPLETE"); } else { glog2(group, "COMPLETE sent"); } set_timeout(group, 0); free(buf); free(encrypted); }
/** * Sends back a STATUS message with the given NAK list */ void send_status(struct group_list_t *group, unsigned int section, const unsigned char *naks, unsigned int nak_count) { unsigned char *buf, *encrypted, *outpacket; struct uftp_h *header; struct status_h *status; struct tfmcc_ack_info_he *tfmcc; unsigned char *sent_naks; int payloadlen, enclen; buf = safe_calloc(MAXMTU, 1); header = (struct uftp_h *)buf; status = (struct status_h *)(buf + sizeof(struct uftp_h)); tfmcc = (struct tfmcc_ack_info_he *)((unsigned char *)status + sizeof(struct status_h)); set_uftp_header(header, STATUS, group); status->func = STATUS; if (group->cc_type == CC_TFMCC) { status->hlen = (sizeof(struct status_h) + sizeof(struct tfmcc_ack_info_he)) / 4; } else { status->hlen = sizeof(struct status_h) / 4; } status->file_id = htons(group->file_id); status->section = htons(section); if (section >= group->fileinfo.big_sections) { payloadlen = (group->fileinfo.secsize_small / 8) + 1; } else { payloadlen = (group->fileinfo.secsize_big / 8) + 1; } if (group->cc_type == CC_TFMCC) { set_tfmcc_ack_info(group, tfmcc); } sent_naks = (unsigned char *)status + (status->hlen * 4); memcpy(sent_naks, naks, payloadlen); payloadlen += status->hlen * 4; if ((group->phase != PHASE_REGISTERED) && (group->keytype != KEY_NONE)) { encrypted = NULL; if (!encrypt_and_sign(buf, &encrypted, payloadlen, &enclen, group->keytype, group->groupkey, group->groupsalt,&group->ivctr, group->ivlen, group->hashtype, group->grouphmackey, group->hmaclen, group->sigtype, group->keyextype, group->client_privkey, group->client_privkeylen)) { glog0(group, "Error encrypting STATUS"); free(buf); return; } outpacket = encrypted; payloadlen = enclen; } else { encrypted = NULL; outpacket = buf; } payloadlen += sizeof(struct uftp_h); if (nb_sendto(listener, outpacket, payloadlen, 0, (struct sockaddr *)&group->replyaddr, family_len(group->replyaddr)) == SOCKET_ERROR) { gsockerror(group, "Error sending STATUS"); } else { glog2(group, "Sent %d NAKs for section %d", nak_count, section); } free(buf); free(encrypted); }
/** * Sends an ABORT message to a server */ void send_abort(int listidx, const char *message) { unsigned char *buf, *encrypted, *outpacket; struct uftp_h *header; struct abort_h *abort; struct uftp2_h *v2_header; char *v2_message; int payloadlen; buf = calloc(group_list[listidx].mtu, 1); if (buf == NULL) { syserror(0, 0, "calloc failed!"); exit(1); } if (group_list[listidx].version == UFTP_V2_VER) { v2_header = (struct uftp2_h *)buf; v2_message = (char *)v2_header + sizeof(struct uftp2_h); v2_header->uftp_id = htonl(V2_UFTP_ID); v2_header->func = htonl(V2_ABORT); v2_header->tx_id = htonl(group_list[listidx].group_id); v2_header->blsize = htonl(strlen(message)); payloadlen = sizeof(struct uftp2_h) + strlen(message); strncpy(v2_message, message, V2_BLOCKSIZE - 1); encrypted = NULL; outpacket = buf; } else { header = (struct uftp_h *)buf; abort = (struct abort_h *)(buf + sizeof(struct uftp_h)); set_uftp_header(header, ABORT, listidx); abort->func = ABORT; abort->host = 0; strncpy(abort->message, message, sizeof(abort->message) - 1); payloadlen = sizeof(struct abort_h); if ((group_list[listidx].phase != PHASE_REGISTERED) && (group_list[listidx].keytype != KEY_NONE)) { encrypted = NULL; if (!encrypt_and_sign(buf, &encrypted, payloadlen, group_list[listidx].mtu, group_list[listidx].keytype, group_list[listidx].groupkey, group_list[listidx].groupsalt, group_list[listidx].ivlen, group_list[listidx].hashtype, group_list[listidx].grouphmackey, group_list[listidx].hmaclen, group_list[listidx].sigtype, group_list[listidx].clientkey, group_list[listidx].client_keylen)) { log0(0, 0, "Error encrypting ABORT"); free(buf); return; } outpacket = encrypted; payloadlen = ntohs(((struct uftp_h *)outpacket)->blsize); } else { encrypted = NULL; outpacket = buf; header->blsize = htons(payloadlen); } payloadlen += sizeof(struct uftp_h); } if (nb_sendto(listener, outpacket, payloadlen, 0, (struct sockaddr *)&group_list[listidx].replyaddr, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { sockerror(group_list[listidx].group_id, group_list[listidx].file_id, "Error sending ABORT"); } file_cleanup(listidx, 1); free(buf); free(encrypted); }
/** * For messages that send a list of clients in the body, append all clients * in the specified state to the packet, then send the message of the given * type when either the body is full or the end of the client list has been * reached. All header fields besides uftp_h.blsize and message.destcount * must be populated before calling. * Returns 1 on success, 0 on fail. */ int send_multiple(const struct finfo_t *finfo, unsigned char *packet, int message, int attempt, uint32_t *addrlist, int state, uint16_t *mes_destcount, int encrypt, const struct sockaddr_in *destaddr, int regconf) { struct uftp_h *header; int hsize, payloadlen; int maxdest, packetcnt, dests, i; unsigned char *mheader, *encpacket, *outpacket; header = (struct uftp_h *)packet; mheader = packet + sizeof(struct uftp_h); hsize = (unsigned char *)addrlist - mheader; maxdest = ((encrypt ? encpayloadsize : payloadsize) - hsize) / sizeof(struct in_addr); packetcnt = 1; if (encrypt) { encpacket = calloc(mtu + keylen, 1); if (encpacket == NULL) { syserror(0, 0, "calloc failed!"); exit(1); } } else { encpacket = NULL; } for (i = 0, dests = 0; i < destcount; i++) { if (message == REG_CONF) { // Only send REG_CONF for a particular client if either it's // behind a proxy or we're sending them to everyone. // Also, don't send if we already sent one and we haven't // gotten another REGISTER if ((destlist[i].status == state) && (!finfo->deststate[i].conf_sent) && (regconf || (destlist[i].proxyidx != -1))) { addrlist[dests++] = destlist[i].addr.s_addr; finfo->deststate[i].conf_sent = 1; } } else if (message == DONE_CONF) { // As with REG_CONF, don't send a DONE_CONF for a client // if we already sent one and we haven't gotten another COMPLETE if ((destlist[i].status == state) && (!finfo->deststate[i].conf_sent)) { addrlist[dests++] = destlist[i].addr.s_addr; finfo->deststate[i].conf_sent = 1; } } else if (destlist[i].status == state) { addrlist[dests++] = destlist[i].addr.s_addr; } if ((dests >= maxdest) || ((i == destcount - 1) && (dests > 0))) { payloadlen = hsize + (dests * sizeof(uint32_t)); *mes_destcount = htons(dests); if (encrypt) { if (!encrypt_and_sign(packet, &encpacket, payloadlen, mtu, keytype, groupkey, groupsalt, ivlen, hashtype, grouphmackey, hmaclen, sigtype, privkey, rsalen)) { log0(0, 0, "Error encrypting %s", func_name(message)); free(encpacket); return 0; } outpacket = encpacket; payloadlen = ntohs(((struct uftp_h *)outpacket)->blsize); } else { outpacket = packet; header->blsize = htons(payloadlen); } log2(0, 0, "Sending %s %d.%d", func_name(message), attempt, packetcnt); log4(0, 0, "Sending to %08X", ntohl(destaddr->sin_addr.s_addr)); if (nb_sendto(sock, outpacket, payloadlen + sizeof(struct uftp_h),0, (struct sockaddr *)destaddr, sizeof(*destaddr)) == SOCKET_ERROR) { sockerror(0, 0, "Error sending %s", func_name(message)); sleep(1); free(encpacket); return 0; } if (packet_wait) usleep(packet_wait); memset(addrlist, 0, maxdest * sizeof(uint32_t)); dests = 0; packetcnt++; } } free(encpacket); return 1; }
/** * Sends a FILEINFO_ACK in response to a FILEINFO */ void send_fileinfo_ack(struct group_list_t *group, int restart) { unsigned char *buf, *encrypted, *outpacket; struct uftp_h *header; struct fileinfoack_h *fileinfo_ack; struct timeval now, send_time; unsigned int payloadlen; int enclen; buf = safe_calloc(MAXMTU, 1); header = (struct uftp_h *)buf; fileinfo_ack = (struct fileinfoack_h *)(buf + sizeof(struct uftp_h)); payloadlen = sizeof(struct fileinfoack_h); set_uftp_header(header, FILEINFO_ACK, group); fileinfo_ack->func = FILEINFO_ACK; fileinfo_ack->hlen = sizeof(struct fileinfoack_h) / 4; fileinfo_ack->file_id = htons(group->file_id); if (restart) { fileinfo_ack->flags |= FLAG_PARTIAL; } gettimeofday(&now, NULL); if (cmptimestamp(now, group->last_server_rx_ts) <= 0) { send_time = group->last_server_ts; } else { send_time = add_timeval(group->last_server_ts, diff_timeval(now, group->last_server_rx_ts)); } fileinfo_ack->tstamp_sec = htonl((uint32_t)send_time.tv_sec); fileinfo_ack->tstamp_usec = htonl((uint32_t)send_time.tv_usec); if (group->keytype != KEY_NONE) { encrypted = NULL; if (!encrypt_and_sign(buf, &encrypted, payloadlen, &enclen, group->keytype, group->groupkey, group->groupsalt,&group->ivctr, group->ivlen, group->hashtype, group->grouphmackey, group->hmaclen, group->sigtype, group->keyextype, group->client_privkey, group->client_privkeylen)) { glog0(group, "Error encrypting FILEINFO_ACK"); free(buf); return; } outpacket = encrypted; payloadlen = enclen; } else { encrypted = NULL; outpacket = buf; } payloadlen += sizeof(struct uftp_h); if (nb_sendto(listener, outpacket, payloadlen, 0, (struct sockaddr *)&(group->replyaddr), family_len(group->replyaddr)) == SOCKET_ERROR) { gsockerror(group, "Error sending FILEINFO_ACK"); } else { glog2(group, "FILEINFO_ACK sent"); } glog3(group, "send time: %d.%06d", send_time.tv_sec, send_time.tv_usec); free(encrypted); free(buf); }