📄 detail.c
字号:
data->fp = NULL; listener->fd = -1; data->state = STATE_UNOPENED; rad_assert(data->vps == NULL); return 0; } /* * Else go read something. */ break; /* * Read more value-pair's, unless we're * at EOF. In that case, queue whatever * we have. */ case STATE_READING: if (!feof(data->fp)) break; data->state = STATE_QUEUED; /* FALL-THROUGH */ case STATE_QUEUED: goto alloc_packet; /* * We still have an outstanding packet. * Don't read any more. */ case STATE_RUNNING: return 0; /* * If there's no reply, keep * retransmitting the current packet * forever. */ case STATE_NO_REPLY: data->state = STATE_QUEUED; goto alloc_packet; /* * We have a reply. Clean up the old * request, and go read another one. */ case STATE_REPLIED: pairfree(&data->vps); data->state = STATE_HEADER; goto do_header; } tail = &data->vps; while (*tail) tail = &(*tail)->next; /* * Read a header, OR a value-pair. */ while (fgets(buffer, sizeof(buffer), data->fp)) { /* * Badly formatted file: delete it. * * FIXME: Maybe flag an error? */ if (!strchr(buffer, '\n')) { pairfree(&data->vps); goto cleanup; } /* * We're reading VP's, and got a blank line. * Queue the packet. */ if ((data->state == STATE_READING) && (buffer[0] == '\n')) { data->state = STATE_QUEUED; break; } /* * Look for date/time header, and read VP's if * found. If not, keep reading lines until we * find one. */ if (data->state == STATE_HEADER) { int y; if (sscanf(buffer, "%*s %*s %*d %*d:%*d:%*d %d", &y)) { data->state = STATE_READING; } continue; } /* * We have a full "attribute = value" line. * If it doesn't look reasonable, skip it. * * FIXME: print an error for badly formatted attributes? */ if (sscanf(buffer, "%255s = %1023s", key, value) != 2) { continue; } /* * Skip non-protocol attributes. */ if (!strcasecmp(key, "Request-Authenticator")) continue; /* * Set the original client IP address, based on * what's in the detail file. * * Hmm... we don't set the server IP address. * or port. Oh well. */ if (!strcasecmp(key, "Client-IP-Address")) { data->client_ip.af = AF_INET; ip_hton(value, AF_INET, &data->client_ip); continue; } /* * The original time at which we received the * packet. We need this to properly calculate * Acct-Delay-Time. */ if (!strcasecmp(key, "Timestamp")) { data->timestamp = atoi(value); vp = paircreate(PW_PACKET_ORIGINAL_TIMESTAMP, PW_TYPE_DATE); if (vp) { vp->vp_date = (uint32_t) data->timestamp; *tail = vp; tail = &(vp->next); } continue; } /* * Read one VP. * * FIXME: do we want to check for non-protocol * attributes like radsqlrelay does? */ vp = NULL; if ((userparse(buffer, &vp) > 0) && (vp != NULL)) { *tail = vp; tail = &(vp->next); } } /* * Some kind of error. * * FIXME: Leave the file in-place, and warn the * administrator? */ if (ferror(data->fp)) goto cleanup; /* * Process the packet. */ alloc_packet: rad_assert(data->state == STATE_QUEUED); /* * We're done reading the file, but we didn't read * anything. Clean up, and don't return anything. */ if (!data->vps) { data->state = STATE_HEADER; return 0; } /* * Allocate the packet. If we fail, it's a serious * problem. */ packet = rad_alloc(1); if (!packet) { radlog(L_ERR, "FATAL: Failed allocating memory for detail"); exit(1); } memset(packet, 0, sizeof(*packet)); packet->sockfd = -1; packet->src_ipaddr.af = AF_INET; packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE); packet->code = PW_ACCOUNTING_REQUEST; packet->timestamp = time(NULL); /* * Remember where it came from, so that we don't * proxy it to the place it came from... */ if (data->client_ip.af != AF_UNSPEC) { packet->src_ipaddr = data->client_ip; } vp = pairfind(packet->vps, PW_PACKET_SRC_IP_ADDRESS); if (vp) { packet->src_ipaddr.af = AF_INET; packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; } else { vp = pairfind(packet->vps, PW_PACKET_SRC_IPV6_ADDRESS); if (vp) { packet->src_ipaddr.af = AF_INET6; memcpy(&packet->src_ipaddr.ipaddr.ip6addr, &vp->vp_ipv6addr, sizeof(vp->vp_ipv6addr)); } } vp = pairfind(packet->vps, PW_PACKET_DST_IP_ADDRESS); if (vp) { packet->dst_ipaddr.af = AF_INET; packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; } else { vp = pairfind(packet->vps, PW_PACKET_DST_IPV6_ADDRESS); if (vp) { packet->dst_ipaddr.af = AF_INET6; memcpy(&packet->dst_ipaddr.ipaddr.ip6addr, &vp->vp_ipv6addr, sizeof(vp->vp_ipv6addr)); } } /* * We've got to give SOME value for Id & ports, so that * the packets can be added to the request queue. * However, we don't want to keep track of used/unused * id's and ports, as that's a lot of work. This hack * ensures that (if we have real random numbers), that * there will be a collision on every 2^(16+15+15+24 - 1) * packets, on average. That means we can read 2^37 * packets before having a collision, which means it's * effectively impossible. */ packet->id = fr_rand() & 0xffff; packet->src_port = 1024 + (fr_rand() & 0x7fff); packet->dst_port = 1024 + (fr_rand() & 0x7fff); packet->dst_ipaddr.af = AF_INET; packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl((INADDR_LOOPBACK & ~0xffffff) | (fr_rand() & 0xffffff)); /* * If everything's OK, this is a waste of memory. * Otherwise, it lets us re-send the original packet * contents, unmolested. */ packet->vps = paircopy(data->vps); /* * Look for Acct-Delay-Time, and update * based on Acct-Delay-Time += (time(NULL) - timestamp) */ vp = pairfind(packet->vps, PW_ACCT_DELAY_TIME); if (!vp) { vp = paircreate(PW_ACCT_DELAY_TIME, PW_TYPE_INTEGER); rad_assert(vp != NULL); pairadd(&packet->vps, vp); } if (data->timestamp != 0) { vp->vp_integer += time(NULL) - data->timestamp; } *pfun = rad_accounting; if (debug_flag) { fr_printf_log("detail_recv: Read packet from %s\n", data->filename_work); for (vp = packet->vps; vp; vp = vp->next) { debug_pair(vp); } } /* * FIXME: many of these checks may not be necessary when * reading from the detail file. * * Try again later... */ if (!received_request(listener, packet, prequest, &data->detail_client)) { rad_free(&packet); data->state = STATE_NO_REPLY; /* try again later */ return 0; } data->state = STATE_RUNNING; return 1;}/* * Free detail-specific stuff. */void detail_free(rad_listen_t *this){ listen_detail_t *data = this->data; free(data->filename); pairfree(&data->vps); if (data->fp != NULL) fclose(data->fp);}int detail_print(rad_listen_t *this, char *buffer, size_t bufsize){ if (!this->server) { return snprintf(buffer, bufsize, "%s", ((listen_detail_t *)(this->data))->filename); } return snprintf(buffer, bufsize, "detail file %s as server %s", ((listen_detail_t *)(this->data))->filename, this->server);}int detail_encode(UNUSED rad_listen_t *this, UNUSED REQUEST *request){ /* * We never encode responses "sent to" the detail file. */ return 0;}int detail_decode(UNUSED rad_listen_t *this, UNUSED REQUEST *request){ /* * We never decode responses read from the detail file. */ return 0;}static const CONF_PARSER detail_config[] = { { "filename", PW_TYPE_STRING_PTR, offsetof(listen_detail_t, filename), NULL, NULL }, { "load_factor", PW_TYPE_INTEGER, offsetof(listen_detail_t, load_factor), NULL, Stringify(10)}, { NULL, -1, 0, NULL, NULL } /* end the list */};/* * Parse a detail section. */int detail_parse(CONF_SECTION *cs, rad_listen_t *this){ int rcode; listen_detail_t *data; RADCLIENT *client; char buffer[2048]; if (!this->data) { this->data = rad_malloc(sizeof(*data)); memset(this->data, 0, sizeof(*data)); } data = this->data; data->delay_time = USEC; rcode = cf_section_parse(cs, data, detail_config); if (rcode < 0) { cf_log_err(cf_sectiontoitem(cs), "Failed parsing listen section"); return -1; } if (!data->filename) { cf_log_err(cf_sectiontoitem(cs), "No detail file specified in listen section"); return -1; } if ((data->load_factor < 1) || (data->load_factor > 100)) { cf_log_err(cf_sectiontoitem(cs), "Load factor must be between 1 and 100"); return -1; } snprintf(buffer, sizeof(buffer), "%s.work", data->filename); free(data->filename_work); data->filename_work = strdup(buffer); /* FIXME: leaked */ data->vps = NULL; data->fp = NULL; data->state = STATE_UNOPENED; /* * Initialize the fake client. */ client = &data->detail_client; memset(client, 0, sizeof(*client)); client->ipaddr.af = AF_INET; client->ipaddr.ipaddr.ip4addr.s_addr = INADDR_NONE; client->prefix = 0; client->longname = client->shortname = data->filename; client->secret = client->shortname; client->nastype = strdup("none"); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -