int tcp_response_waiting_client_close_process (Context *cont) { const char *fn = "tcp_response_waiting_client_close_process()"; uint16_t length_buf; int i; syslog (LOG_DEBUG, "%s: start", fn); i = read (cont->conn_sock, (u_char *) (&length_buf), sizeof (uint16_t)); if (!i) /* SUCCESS */ return tcp_response_finish (cont); if (i < sizeof (uint16_t)) { /* read error */ syslog (LOG_INFO, "%s: read(): %m", fn); return (response_abort (cont, -1)); } /* redo query processing */ length_buf = ntohs (length_buf); syslog (LOG_DEBUG, "%s: incoming length %d", fn, length_buf); /* free old buffer */ if (cont->mesg.p) free (cont->mesg.p); /* allocate new buffer */ cont->mesg.p = malloc (length_buf); if (!cont->mesg.p) { cont->mesg_len = 0; return (response_abort (cont, -1)); } cont->mesg_len = length_buf; cont->wp = cont->mesg.p; cont->timeout = TCP_SRV_TIMEOUT; /* renew timeout */ if (cont->tout) cont->tout->handler = NULL; if (context_timeout_register (cont, cont->timeout)) return (response_abort (cont, -1)); /* * I/O event is not changed -- tcp_conn_in, * go back to reading */ cont->process = tcp_response_reading_process; cont->retry = tcp_response_reading_retry; syslog (LOG_DEBUG, "%s: return, continue reading", fn); /* SUCCESS, but not FINISHED yet */ return 0; }
int tcp_response_readlen_process (Context *cont) { const char *fn = "tcp_response_readlen_process()"; uint16_t length_buf; syslog (LOG_DEBUG, "%s: start", fn); /* renew timeout */ if (cont->tout) cont->tout->handler = NULL; if (context_timeout_register (cont, cont->timeout)) return (response_abort (cont, -1)); /* still use old input list -- data following */ /* read length buffer */ if (read (cont->conn_sock, (u_char *) (&length_buf), sizeof (uint16_t)) < sizeof (uint16_t)) { syslog (LOG_NOTICE, "%s: cannot read length TCP message", fn); return (response_abort (cont, -1)); } length_buf = ntohs (length_buf); syslog (LOG_DEBUG, "%s: data length = %d", fn, length_buf); /* free old buffer */ if (cont->mesg.p) free (cont->mesg.p); /* allocate new properly sized buffer */ cont->mesg.p = malloc (length_buf); if (!cont->mesg.p) return (response_abort (cont, -1)); cont->mesg_len = length_buf; cont->wp = cont->mesg.p; /* go next state */ cont->process = tcp_response_reading_process; cont->retry = tcp_response_reading_retry; /* SUCCESS */ return 0; }
int tcp_response_recursive_process (Context *cont) { const char *fn = "tcp_response_recursive_process()"; syslog (LOG_DEBUG, "%s: start", fn); switch (recursive_process (cont)) { case 0: syslog (LOG_DEBUG, "%s: return, continue", fn); /* SUCCESS */ return 0; case 1: assemble_response (cont); if (cont->mesg_len < 0 || cont->mesg_len > MAX_STREAM) { syslog (LOG_WARNING, "response message too big"); return (response_abort (cont, 1)); } if (cont->tout) cont->tout->handler = NULL; if (context_timeout_register (cont, cont->timeout)) return (response_abort (cont, -1)); /* register output */ if (ev_tcp_out_register (cont->conn_sock, cont)) return (response_abort (cont, -1)); /* change the state */ cont->process = tcp_response_writing_process; cont->retry = tcp_response_writing_retry; cont->wp = NULL; syslog (LOG_DEBUG, "%s: return, finish", fn); /* SUCCESS */ return 0; default: return (response_abort (cont, -1)); } }
/* * When a new query is received over a UDP socket from a client, the * udp_response state machine is started. See also ev_udp_in_read(), * which is the only place from where udp_response_start() is called. * * udp_response_start() starts a new transaction. First creates a new * root context for it, and starts the forwarding of the original query. * * forwarding is performed by starting a new child request, which * if all goes well result in some resource records in our context. * * when the forwarded request finished successfully, udp_response_finish() * is responsible for interpreting it and sending a response back to the client. * */ int udp_response_start (u_char *mesg_buf, int mesg_len, struct sockaddr *sa_p, Nia *inif) { const char *fn = "udp_response_start()"; Context *cont; syslog (LOG_DEBUG, "%s: start", fn); /* create context */ cont = context_create(); if (!cont) return (response_abort (cont, -1)); cont->mesg.p = mesg_buf; cont->mesg_len = mesg_len; cont->wp = mesg_buf + mesg_len; /* just after the answer section */ cont->q_id = cont->mesg.hdr->id; cont->netifaddr = nia_copy (inif); memcpy (cont->peer, sa_p, SOCKADDR_SIZEOF(*sa_p)); if (cont->mesg.hdr->opcode == OP_QUERY) { syslog (LOG_DEBUG, "%s: OPCODE = OP_QUERY", fn); /* query-response specific variables */ cont->process = udp_response_recursive_process; cont->retry = udp_response_recursive_retry; /* do the forwarding, send request to forwarder */ switch (request_start (cont, QUERY_TCP)) { case 0: /* We got a response */ return (0); case 1: /* Something wrong with the query */ cont->mesg.hdr->rcode = RC_FMTERR; return (udp_response_finish (cont)); default: /* We failed ourselves somehow */ cont->mesg.hdr->rcode = RC_SERVERERR; return (udp_response_finish (cont)); } } else { syslog (LOG_NOTICE, "%s: OPCODE unknown(%d)", fn, cont->mesg.hdr->opcode); cont->mesg.hdr->rcode = RC_NIMP; return udp_response_finish (cont); } /* NOTREACHED */ return 0; }
int tcp_response_start (int sock, struct sockaddr *sa_p) { const char *fn = "tcp_response_start()"; Context *cont; syslog (LOG_DEBUG, "%s: start", fn); cont = context_create(); if (!cont) return (response_abort (cont, -1)); cont->process = tcp_response_readlen_process; cont->retry = tcp_response_readlen_retry; memcpy (cont->peer, sa_p, SOCKADDR_SIZEOF(*sa_p)); cont->conn_sock = sock; cont->timeout = TCP_SRV_TIMEOUT; if (!context_timeout_register (cont, cont->timeout) && !ev_tcp_conn_in_register (cont->conn_sock, cont)) return 0; /* SUCCESS */ return (response_abort (cont, -1)); }
int tcp_response_writing_process (Context *cont) { const char *fn = "tcp_response_writing_process()"; syslog (LOG_DEBUG, "%s: start", fn); /* renew timeout */ if (cont->tout) cont->tout->handler = NULL; if (context_timeout_register (cont, cont->timeout)) return (response_abort (cont, -1)); switch (tcp_writemesg (cont, cont->conn_sock)) { case 0: /* continue this process */ syslog (LOG_DEBUG, "%s: return, continue", fn); /* SUCCESS */ return 0; case 1: /* all data written */ cont->process = tcp_response_waiting_client_close_process; cont->retry = tcp_response_waiting_client_close_retry; /* stop output and waiting for input */ ev_tcp_out_remove (cont->conn_sock); ev_tcp_conn_in_register (cont->conn_sock, cont); syslog (LOG_DEBUG, "%s: return, finish", fn); /* SUCCESS */ return 0; default: /* FAILURE */ return (response_abort (cont, -1)); } }
int udp_response_recursive_retry (Context *cont) { syslog (LOG_ERR, "udp_response_recursive_retry should not be called."); return response_abort (cont, 0); }
int udp_response_finish (Context *cont) { const char *fn = "udp_response_finish()"; int len; syslog (LOG_DEBUG, "%s: start", fn); /* * We trim the response down if it doesn't fit in a default UDP * data in a somewhat crude way. Could be smarter, like trim * A records from response for pure IPv6 queries and so. See, if * it is needed often. Maybe better to support EDNS0 option instead. * * RFC1035 says we should truncate the message to 512 bytes and set the * tr bit in the header, but it is really vague on when a response does * not fit. RFC2181 clarifies the use of the tr bit in section 9. * * Note that similar logic is still present in mesg_assemble() in * ne_mesg.c (may disappear if we add the logic to assemble_response() * instead). */ assemble_response (cont); if (cont->mesg_len < 0 || cont->mesg_len > MAX_PACKET) { /* put the message on a diet */ list_destroy (cont->ar_list, rrset_freev); cont->ar_list = NULL; syslog (LOG_DEBUG, "Overweight, dropping additional section"); assemble_response (cont); } if (cont->mesg_len < 0 || cont->mesg_len > MAX_PACKET) { /* * ok, water adn bread then then. shuold check * RFCs, it may be better to return error msg * instead of slimmed answer. */ list_destroy (cont->ns_list, rrset_freev); cont->ns_list = NULL; syslog (LOG_DEBUG, "Overweight, dropping authority section"); assemble_response (cont); } if (cont->mesg_len < 0 || cont->mesg_len > MAX_PACKET) { /* ok, nothing viable left, so die */ list_destroy (cont->an_list, rrset_freev); cont->an_list = NULL; assemble_response (cont); cont->mesg.hdr->tc = 1; syslog (LOG_WARNING, "Obese, answers too big for UDP"); } if (cont->mesg_len < 0 || cont->mesg_len > MAX_PACKET) { syslog (LOG_ERR, "Even error msg is too big for UDP"); return (response_abort (cont, 1)); } /* send the answer */ len = net_mesg_send (cont->netifaddr, cont->mesg.p, cont->mesg_len, cont->peer); if (len < cont->mesg_len) { syslog (LOG_NOTICE, "failed to send message."); return (response_abort (cont, -1)); } context_destroy (cont); return 0; }
int tcp_response_reading_process (Context *cont) { const char *fn = "tcp_response_reading_process()"; int len; syslog (LOG_DEBUG, "%s: start", fn); if (cont->tout) cont->tout->handler = NULL; if (context_timeout_register (cont, cont->timeout)) return(response_abort (cont, -1)); len = read (cont->conn_sock, cont->wp, cont->mesg_len - (cont->wp - cont->mesg.p)); if (len <= 0) return(response_abort (cont, -1)); cont->wp += len; if (cont->wp < (cont->mesg.p + cont->mesg_len)) { syslog (LOG_DEBUG, "%s: left %zd bytes -- continue.", fn, (cont->mesg.p + cont->mesg_len) - cont->wp); /* SUCCESS */ return 0; /* the processing continues ... */ } /* all data has been read now */ ev_tcp_conn_in_remove (cont->conn_sock); if (cont->mesg.hdr->opcode == OP_QUERY) { if (cont->tout) cont->tout->handler = NULL; /* * don't register input list, * child context takes input */ switch (request_start (cont, QUERY_TCP)) { case 0: /* * We forwarded the request without problems, * asycnhronously awaiting a response. * goto recursive_processing state * clear events, child will call me then */ if (cont->tout) cont->tout->handler = NULL; cont->process = tcp_response_recursive_process; cont->retry = tcp_response_recursive_retry; /* SUCCESS */ return 0; case 1: /* Something wrong with the query */ syslog (LOG_NOTICE, "%s: Request failed", fn); cont->mesg.hdr->rcode = RC_FMTERR; default: /* totd failed itself somehow */ syslog (LOG_NOTICE, "%s: Totd failed", fn); cont->mesg.hdr->rcode = RC_SERVERERR; } } else cont->mesg.hdr->rcode = RC_NIMP; /* * Not OP_QUERY or Request failed brings us here * * Go to writing state. Timeout already done in this function * Register new output event */ if (!ev_tcp_out_register (cont->conn_sock, cont)) { assemble_response (cont); /* state change */ cont->process = tcp_response_writing_process; cont->retry = tcp_response_writing_retry; cont->wp = NULL; syslog (LOG_DEBUG, "%s: end (writing:)", fn); /* SUCCESS */ return 0; } /* FAILURE */ return (response_abort (cont, -1)); }
int tcp_response_readlen_retry (Context *cont) { const char *fn = "tcp_response_readlen_retry()"; syslog (LOG_NOTICE, "%s: connection does not respond. closing.", fn); return (response_abort (cont, -1)); }
int tcp_response_waiting_client_close_retry (Context *cont) { return (response_abort (cont, 0)); }
int tcp_response_writing_retry (Context *cont) { return (response_abort (cont, -1)); }
int tcp_response_recursive_retry (Context *cont) { return (response_abort (cont, -1)); }