/* Posadis - A DNS Server A DNS file server using the Posadis server library Copyright (C) 2002 Meilof Veeningen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define POS_DEFAULTLOG #define POS_DEFAULTLOG_STDERR #define POS_DEFAULTLOG_SYSLOG #define POS_DEFAULTLOG_FILE #include #include #include #include #include #include #include #include DnsMessage *my_handle_query(pending_query *query); void cleanup(int sig) { pos_setquitflag(); } char *path; int main(int argc, char **argv) { _addr a; try { /* get command-line arguments */ if (argc == 2) { if (argv[1][0] == '@') { txt_to_addr(&a, argv[1] + 1); path = "."; } else { path = argv[1]; txt_to_addr(&a, "0.0.0.0"); } } else if (argc == 3 && argv[1][0] == '@') { /* address given */ txt_to_addr(&a, argv[1] + 1); path = argv[2]; } else if (argc != 1) { printf("Usage: fileserver [@interface] [dir]\n"); return 1; } else { path = "."; /* current directory */ txt_to_addr(&a, "0.0.0.0"); } if (chdir(path) < 0) { perror("Could not chdir to exported directory"); return 1; } /* bring up posadis */ servers.push_front(ServerSocket(ss_udp, udpcreateserver(&a))); servers.push_front(ServerSocket(ss_tcp, tcpcreateserver(&a))); pos_log(context_none, log_info, "Posadis fileserver [%s] starting up...", path); signal(SIGINT, cleanup); signal(SIGTERM, cleanup); handle_query = my_handle_query; posserver_run(); } catch (PException p) { printf("Fatal exception: %s\n", p.message); return 1; } return 0; } /* the entry function which will handle all queries */ DnsMessage *my_handle_query(pending_query *query) { DnsMessage *a = new DnsMessage(); DnsQuestion q; DnsRR rr; a->ID = query->message->ID; if (query->message->questions.begin() == query->message->questions.end()) { a->RCODE = RCODE_QUERYERR; return a; } q = *query->message->questions.begin(); /* now, map the domain name to a file name */ stl_string fname = ""; stl_string substr; int x, n; n = q.QNAME.nlabels(); for (x = n - 1; x >= 0; x--) { if (!fname.empty()) fname += "/"; substr = q.QNAME.label(x); if (substr.find("/") != string::npos) substr = substr.replace(substr.find("/"), 1, "."); fname += substr; } /* check for some common pitfalls */ if (fname.find("..") != string::npos || fname[0] == '/') { a->RCODE = RCODE_QUERYERR; return a; } /* see if we have a directory */ DIR *dir = opendir(fname.c_str()), *d2; struct dirent *info; char curfname[PATH_MAX]; if (dir) { /* yes! */ while ((info = readdir(dir)) != NULL) { if (strlen(info->d_name) <= 254 && strlen(info->d_name) + strlen(fname.c_str()) + 2 <= PATH_MAX) { strcpy(curfname, fname.c_str()); strcat(curfname, "/"); strcat(curfname, info->d_name); d2 = opendir(curfname); strcpy(curfname, info->d_name); if (d2) { strcat(curfname, "/"); closedir(d2); } rr = DnsRR(q.QNAME, DNS_TYPE_TXT, CLASS_IN, 3600); rr.RDLENGTH = strlen(curfname) + 1; rr.RDATA = (char *)malloc(rr.RDLENGTH); rr.RDATA[0] = strlen(curfname); memcpy(rr.RDATA + 1, curfname, strlen(curfname)); a->answers.push_back(rr); } } closedir(dir); } else { /* try to open file */ FILE *f = fopen(fname.c_str(), "r"); int len; if (f) { fseek(f, 0, SEEK_END); len = ftell(f); fseek(f, 0, SEEK_SET); if (len <= 65000) { rr = DnsRR(q.QNAME, DNS_TYPE_NULL, CLASS_IN, 3600); rr.RDLENGTH = len; rr.RDATA = (char *)malloc(len); fread(rr.RDATA, 1, len, f); a->answers.push_back(rr); } else { a->TC = true; } fclose(f); } else { if (f) fclose(f); a->RCODE = RCODE_NXDOMAIN; } } return a; }