diff options
Diffstat (limited to 'contrib/idn/mdnkit/dnsproxy/message.c')
-rw-r--r-- | contrib/idn/mdnkit/dnsproxy/message.c | 627 |
1 files changed, 627 insertions, 0 deletions
diff --git a/contrib/idn/mdnkit/dnsproxy/message.c b/contrib/idn/mdnkit/dnsproxy/message.c new file mode 100644 index 00000000..230ca9b5 --- /dev/null +++ b/contrib/idn/mdnkit/dnsproxy/message.c @@ -0,0 +1,627 @@ +/* + * message.c - mDNS Proxy, message handling + * + * message will passed with callback 'notify_message'. + * this module parse received message and forward request, + * or reply to originator + */ + +/* + * Copyright (c) 2000 Japan Network Information Center. All rights reserved. + * + * By using this file, you agree to the terms and conditions set forth bellow. + * + * LICENSE TERMS AND CONDITIONS + * + * The following License Terms and Conditions apply, unless a different + * license is obtained from Japan Network Information Center ("JPNIC"), + * a Japanese association, Fuundo Bldg., 1-2 Kanda Ogawamachi, Chiyoda-ku, + * Tokyo, Japan. + * + * 1. Use, Modification and Redistribution (including distribution of any + * modified or derived work) in source and/or binary forms is permitted + * under this License Terms and Conditions. + * + * 2. Redistribution of source code must retain the copyright notices as they + * appear in each source code file, this License Terms and Conditions. + * + * 3. Redistribution in binary form must reproduce the Copyright Notice, + * this License Terms and Conditions, in the documentation and/or other + * materials provided with the distribution. For the purposes of binary + * distribution the "Copyright Notice" refers to the following language: + * "Copyright (c) Japan Network Information Center. All rights reserved." + * + * 4. Neither the name of JPNIC may be used to endorse or promote products + * derived from this Software without specific prior written approval of + * JPNIC. + * + * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * 6. Indemnification by Licensee + * Any person or entities using and/or redistributing this Software under + * this License Terms and Conditions shall defend indemnify and hold + * harmless JPNIC from and against any and all judgements damages, + * expenses, settlement liabilities, cost and other liabilities of any + * kind as a result of use and redistribution of this Software or any + * claim, suite, action, litigation or proceeding by any third party + * arising out of or relates to this License Terms and Conditions. + * + * 7. Governing Law, Jurisdiction and Venue + * This License Terms and Conditions shall be governed by and and + * construed in accordance with the law of Japan. Any person or entities + * using and/or redistributing this Software under this License Terms and + * Conditions hereby agrees and consent to the personal and exclusive + * jurisdiction and venue of Tokyo District Court of Japan. + */ + +#ifndef lint +static char *rcsid = "$Id: message.c,v 1.1 2000/12/07 00:52:19 tale Exp $"; +#endif + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifdef WIN32 +#include <windows.h> +#include <winsock.h> +#else /* for normal systems */ +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#endif + +#include "dnsproxy.h" + +/* + * address handling utilities + * + * addrEq check same addresses + * addrFmt format address, port & protocol + * + * these functions are same with those in 'server.c'. + * may be put in another 'utility' module. + */ + +static BOOL addrEq(struct sockaddr *a1, struct sockaddr *a2) +{ + struct sockaddr_in *ip1 = (struct sockaddr_in *) a1 ; + struct sockaddr_in *ip2 = (struct sockaddr_in *) a2 ; + + if (ip1->sin_addr.s_addr != ip2->sin_addr.s_addr) { + return FALSE ; + } + if (ip1->sin_port != ip2->sin_port) { + return FALSE ; + } + return TRUE ; +} + +static u_char fmtbuff[64] ; + +static u_char *addrFmt(struct sockaddr *addr, int proto) +{ + struct sockaddr_in *iaddr = (struct sockaddr_in *) addr ; + u_char *ap ; + u_char *pp ; + + ap = (u_char *) &iaddr->sin_addr ; + pp = (u_char *) &iaddr->sin_port ; + + sprintf(fmtbuff, "%s:%d.%d.%d.%d:%d", + (proto == SOCK_STREAM ? "TCP" : "UDP"), + (ap[0] & 0xff), (ap[1] & 0xff), (ap[2] & 0xff), (ap[3] & 0xff), + ((pp[0] & 0xff) * 256 + (pp[1] & 0xff)) ) ; + + return fmtbuff ; +} + +/* + * Managing Message ID + */ + +static u_short msgidLast = 0xffff ; +static u_short msgidMap[4096] = { 0 } ; + +#define ID_INDEX(x) (((x) & 0xfff0) >> 4) +#define ID_MASK(x) (1 << ((x) & 0x000f)) + +#define ID_CHECK(x) (msgidMap[ID_INDEX((x))] & ID_MASK((x))) +#define ID_USEIT(x) (msgidMap[ID_INDEX((x))] |= ID_MASK((x))) +#define ID_CLEAR(x) (msgidMap[ID_INDEX((x))] &= ~ID_MASK((x))) + +static BOOL idAlloc(u_short *id) +{ + u_short newid ; + + for (newid = (msgidLast + 1) & 0xffff ; + newid != msgidLast ; + newid = (newid + 1) & 0xffff) { + if (ID_CHECK(newid) == 0) { + ID_USEIT(newid) ; + msgidLast = newid ; + *id = newid ; + return TRUE ; + } + } + WARN("idAlloc - no more ID\n") ; + return FALSE ; +} + +static void idFree(u_short id) +{ + if (ID_CHECK(id) == 0) { + WARN("idAlloc - %04x is not in use\n", id) ; + return ; + } + ID_CLEAR(id) ; +} + +/* + * Message Managements + * + * Request from client is identified with its ID word. It is unique + * on one client, but proxy accepts requests from multiple clients, + * proxy cannot distinguish request with ID only, and cannot forward + * request with such ID word. + * + * So, proxy will identify requests with combination of address, port, + * (which identified client) and ID word. Then forwarding request, + * proxy allocate unique ID, and change request's ID with new one. + * + * Response from DNS server will identified with newly allocated ID. + * For responding such response to originator, replace response's + * ID with original one, and send response to marked address/port. + */ + +typedef struct _MSG *MSGPTR ; + +typedef struct _MSG { + MSGPTR prev ; + MSGPTR next ; + time_t last ; + struct sockaddr from ; + int proto ; + u_short orgId ; + u_short newId ; + translation_context_t trctx ; +} MSGREC ; + +static MSGREC listMsg = { 0 } ; + +/* + * searchReq - search request in message list, search on original ID + */ + +static MSGPTR searchReq(u_short id, int proto, struct sockaddr *addr) +{ + MSGPTR p ; + + if (listMsg.prev == NULL || listMsg.next == NULL) { + listMsg.prev = &listMsg ; + listMsg.next = &listMsg ; + } + for (p = listMsg.next ; p != &listMsg ; p = p->next) { + if (p->orgId != id || p->proto != proto) { + continue ; + } + if (addrEq(&p->from, addr) != TRUE) { + continue ; + } + p->last = time(NULL) ; + return p ; + } + return NULL ; +} + +/* + * searchOrg - search original request matching to new ID + */ + +static MSGPTR searchOrg(u_short id, int proto) +{ + MSGPTR p ; + + if (listMsg.prev == NULL || listMsg.next == NULL) { + listMsg.prev = &listMsg ; + listMsg.next = &listMsg ; + } + for (p = listMsg.next ; p != &listMsg ; p = p->next) { + if (p->newId != id || p->proto != proto) { + continue ; + } + p->last = time(NULL) ; + return p ; + } + return NULL ; +} + +/* + * createReq - create new message record for new request + * + * it also allocate new ID for this request, used for + * forwarding this request + */ + +static MSGPTR createReq(u_short id, int proto, struct sockaddr *addr) +{ + u_short newid ; + MSGPTR pMsg, prev, next ; + + if (listMsg.prev == NULL || listMsg.next == NULL) { + listMsg.prev = &listMsg ; + listMsg.next = &listMsg ; + } + + if (idAlloc(&newid) != TRUE) { + WARN("createReq - no more ID\n") ; + return NULL ; + } + if ((pMsg = (MSGPTR) malloc(sizeof(MSGREC))) == NULL) { + WARN("createReq - cannot allocate message record\n") ; + idFree(newid) ; + return NULL ; + } + + memset(pMsg, 0, sizeof(MSGREC)) ; + + memcpy(&pMsg->from, addr, sizeof(struct sockaddr)) ; + pMsg->proto = proto ; + pMsg->orgId = id ; + pMsg->newId = newid ; + pMsg->last = time(NULL) ; + + pMsg->trctx.client = &pMsg->from ; + pMsg->trctx.protocol = pMsg->proto ; + pMsg->trctx.old_id = pMsg->orgId ; + pMsg->trctx.new_id = pMsg->newId ; + + prev = listMsg.prev ; + next = prev->next ; + + prev->next = pMsg ; + next->prev = pMsg ; + pMsg->prev = prev ; + pMsg->next = next ; + + return pMsg ; +} + +/* + * disposeReq - dispose message record + */ + +static void disposeReq(MSGPTR pMsg) +{ + MSGPTR p ; + + if (listMsg.prev == NULL || listMsg.next == NULL) { + listMsg.prev = &listMsg ; + listMsg.next = &listMsg ; + } + + for (p = listMsg.next ; p != &listMsg ; p = p->next) { + if (p == pMsg) { + break ; + } + } + if (p == pMsg) { /* safe to unlink it */ + pMsg->prev->next = pMsg->next ; + pMsg->next->prev = pMsg->prev ; + } + idFree(pMsg->newId) ; + free(pMsg) ; +} + +/* + * messageForward - forward the request + */ + +static void errorOnRequest(MSGPTR pMsg, u_char *msg, int len, size_t err) +{ + u_short errmsg[6] ; + u_short flags ; + u_short *ps ; + + TRACE("errorOnRequest %d\n", err) ; + + ps = (u_short *) msg ; + flags = ntohs(ps[1]) ; + flags = ((flags & 0x7fff) | 0x8000) ; /* QR to response */ + flags = ((flags & 0xfff8) | (err & 0x0007)) ; /* set RCODE */ + + memset(errmsg, 0, sizeof(errmsg)) ; + errmsg[0] = htons(pMsg->orgId) ; + errmsg[1] = htons(flags) ; + + server_response(&pMsg->from, pMsg->proto, (u_char *) errmsg, sizeof(errmsg)) ; +} + +static void messageForward(MSGPTR pMsg, u_char *msg, int len) +{ + u_short *p ; + u_char buff[1024] ; + u_char *bbase ; + size_t bleng ; + size_t cleng = 0 ; /* avoid un-expected length on xlate error */ + size_t cstat = 0 ; /* avoid un-expected status on xlate error */ + + TRACE("messageForward - %04x -> %04x\n", pMsg->orgId, pMsg->newId) ; + + /* + * prepare conversion buffer + */ + + if (len < sizeof(buff) / 2) { + bbase = buff ; + bleng = sizeof(buff) ; + } else { + bbase = malloc(len * 2) ; + bleng = len * 2 ; + } + if (bbase == NULL) { + WARN("messageForward - cannot prepare conversion buffer\n") ; + return ; + } + + /* + * translate message (domain names) + */ + + TRACE("messageForward - translate request\n") ; + + cstat = translate_request(&pMsg->trctx, msg, len, bbase, bleng, &cleng) ; + + TRACE("messageForward - translated status %d length %d\n", cstat, cleng) ; + + if (cstat != 0) { /* error on conversion */ + WARN("messageForward - translation error %d\n", cstat) ; + errorOnRequest(pMsg, msg, len, cstat) ; + return ; + } + if (pMsg->proto == SOCK_DGRAM && cleng > 512) { + WARN("messageForward - translation overflow %d\n", cleng) ; + errorOnRequest(pMsg, msg, len, 2) ; + return ; + } + + /* + * forward the request + */ + + p = (u_short *) bbase ; + p[0] = htons(pMsg->newId) ; + + server_forward(NULL, pMsg->proto, bbase, cleng) ; + + /* + * cleanup buffer + */ + + if (bbase != buff) { + free(bbase) ; + } +} + +/* + * messageResponse - response to originating client + */ + +static void errorOnResponse(MSGPTR pMsg, u_char *msg, int len, size_t err) +{ + u_short errmsg[6] ; + u_short flags ; + u_short *ps ; + + TRACE("errorOnResponse %d\n", err) ; + + ps = (u_short *) msg ; + flags = ntohs(ps[1]) ; + flags = ((flags & 0x7fff) | 0x8000) ; /* QR to response */ + flags = ((flags & 0xfff8) | (err & 0x0007)) ; /* set RCODE */ + + memset(errmsg, 0, sizeof(errmsg)) ; + errmsg[0] = htons(pMsg->orgId) ; + errmsg[1] = htons(flags) ; + + server_response(&pMsg->from, pMsg->proto, (u_char *) errmsg, sizeof(errmsg)) ; +} + +static void messageResponse(MSGPTR pMsg, u_char *msg, int len) +{ + u_short *p ; + u_char buff[1024] ; + u_char *bbase ; + size_t bleng ; + size_t cleng ; + size_t cstat ; + + TRACE("messageResponse - %04x <- %04x\n", pMsg->orgId, pMsg->newId) ; + + /* + * prepare conversion buffer + */ + + if (len < sizeof(buff) / 2) { + bbase = buff ; + bleng = sizeof(buff) ; + } else { + bbase = malloc(len * 2) ; + bleng = len * 2 ; + } + if (bbase == NULL) { + WARN("messageResponse - cannot prepare conversion buffer\n") ; + return ; + } + + /* + * translate message (domain names) + */ + + TRACE("messageResponse - translate response\n") ; + + cstat = translate_reply(&pMsg->trctx, msg, len, bbase, bleng, &cleng) ; + + TRACE("messageResponse - translated status %d length %d\n", cstat, cleng) ; + + if (cstat != 0) { /* error on conversion */ + WARN("messageResponse - translation error %d\n", cstat) ; + errorOnResponse(pMsg, msg, len, cstat) ; + return ; + } + if (pMsg->proto == SOCK_DGRAM && cleng > 512) { + WARN("messageResponse - translation overflow %d\n", cleng) ; + errorOnResponse(pMsg, msg, len, 2) ; + return ; + } + + /* + * reply back to requester + */ + + p = (u_short *) bbase ; + p[0] = htons(pMsg->orgId) ; + + server_response(&pMsg->from, pMsg->proto, bbase, cleng) ; + + /* + * cleanup buffer + */ + + if (bbase != buff) { + free(bbase) ; + } +} + +/* + * notify_message - callback from server loop + */ + +void notify_message(struct sockaddr *from, int proto, u_char *msg, int len) +{ + u_short *p = (u_short *) msg ; + u_short msgid, flags ; + MSGPTR pMsg ; +#ifdef DEBUG + char logbuf[256] ; +#endif + + msgid = ntohs(p[0]) ; + flags = ntohs(p[1]) ; + +#ifdef DEBUG + if ((flags & 0x8000) == 0) { + sprintf(logbuf, "Request %04x (%04x) from %s, %d bytes", + msgid, flags, addrFmt(from, proto), len) ; + } else { + sprintf(logbuf, "Response %04x (%04x) from %s %d bytes", + msgid, flags, addrFmt(from, proto), len) ; + } + TRACE("%s\n", logbuf) ; + + strcpy(logbuf, " ") ; + + switch ((flags & 0x7800) >> 11) { + case 0 : strcat(logbuf, "QUERY ") ; break ; + case 1 : strcat(logbuf, "IQUERY ") ; break ; + case 2 : strcat(logbuf, "STATUS ") ; break ; + default : strcat(logbuf, "UNKNOWN") ; break ; + } + if ((flags & 0x0400) != 0) { + strcat(logbuf, ",AA") ; + } + if ((flags & 0x0200) != 0) { + strcat(logbuf, ",TC") ; + } + if ((flags & 0x0100) != 0) { + strcat(logbuf, ",RD") ; + } + if ((flags & 0x0080) != 0) { + strcat(logbuf, ",RA") ; + } + switch (flags & 0x00f) { + case 0 : strcat(logbuf, ",No Error ") ; break ; + case 1 : strcat(logbuf, ",Format Error ") ; break ; + case 2 : strcat(logbuf, ",Server Failure ") ; break ; + case 3 : strcat(logbuf, ",Name Error ") ; break ; + case 4 : strcat(logbuf, ",Not Implemented") ; break ; + case 5 : strcat(logbuf, ",Refused ") ; break ; + default : strcat(logbuf, ",Unknown Error ") ; break ; + } + TRACE("%s\n", logbuf) ; +#endif + + if ((flags & 0x8000) == 0) { /* request from client */ + + if ((pMsg = searchReq(msgid, proto, from)) == NULL) { + pMsg = createReq(msgid, proto, from) ; + } + if (pMsg == NULL) { + WARN("notify_message - cannot create message record\n") ; + return ; + } + messageForward(pMsg, msg, len) ; + + } else { /* response from server */ + + if ((pMsg = searchOrg(msgid, proto)) == NULL) { + WARN("notify_message - no corresponding request\n") ; + return ; + } + messageResponse(pMsg, msg, len) ; + disposeReq(pMsg); + } +} + +/* + * notify_timer - timer callback + */ + +static time_t timeLastCheck = 0 ; +static time_t timeInterval = 60 ; +static time_t timeTimeout = (60 * 10) ; + +void notify_timer(void) +{ + time_t t = time(NULL) ; + MSGPTR p, np ; +#ifdef DEBUG + int ndiscarded = 0; +#endif + + if (listMsg.prev == NULL || listMsg.next == NULL) { + listMsg.prev = &listMsg ; + listMsg.next = &listMsg ; + } + + if ((t - timeLastCheck) < timeInterval) { + return ; + } + for (p = listMsg.next ; p != &listMsg ; p = np) { + np = p->next ; + if ((t - p->last) > timeTimeout) { + disposeReq(p) ; +#ifdef DEBUG + ndiscarded++; +#endif + } + } +#ifdef DEBUG + TRACE("notify_timer: %d discarded\n", ndiscarded); +#endif + timeLastCheck = t; +} |