diff options
Diffstat (limited to 'plugins/dns')
-rw-r--r-- | plugins/dns/makefile.mak | 19 | ||||
-rw-r--r-- | plugins/dns/plugin-dns.c | 335 | ||||
-rw-r--r-- | plugins/dns/thread.c | 111 |
3 files changed, 465 insertions, 0 deletions
diff --git a/plugins/dns/makefile.mak b/plugins/dns/makefile.mak new file mode 100644 index 00000000..f1dd4c73 --- /dev/null +++ b/plugins/dns/makefile.mak @@ -0,0 +1,19 @@ +include "..\..\src\makeinc.mak" + +xcdns.dll: plugin-dns.obj dns.def + link $(LDFLAGS) /dll /out:xcdns.dll /def:dns.def plugin-dns.obj ws2_32.lib + dir xcdns.dll + +dns.def: + echo EXPORTS > dns.def + echo xchat_plugin_init >> dns.def + echo xchat_plugin_deinit >> dns.def + +plugin-dns.obj: plugin-dns.c makefile.mak thread.c + cl $(CFLAGS) /I.. -Dsnprintf=_snprintf plugin-dns.c + +clean: + del *.obj + del *.dll + del *.exp + del *.lib diff --git a/plugins/dns/plugin-dns.c b/plugins/dns/plugin-dns.c new file mode 100644 index 00000000..fdefd490 --- /dev/null +++ b/plugins/dns/plugin-dns.c @@ -0,0 +1,335 @@ +/* XChat Win32 DNS Plugin + * Copyright (C) 2003-2004 Peter Zelezny. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +/* + * Requires MS Visual Studio and IPV6 headers to compile (run nmake). + * Compiling with gcc (mingw) will fail due to missing gai_strerror. + */ + +#define DNS_VERSION "2.4" + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> + +#define IPV6 + +#ifdef _WIN32 +#ifdef IPV6 +#include <winsock2.h> +#include <ws2tcpip.h> +#else +#include <winsock2.h> +#endif +#else +#include <netdb.h> +#include <sys/socket.h> +#endif + +#include "xchat-plugin.h" +#include "thread.c" + +#define HELP "Usage: DNS <nickname|hostname|numerical address>\n" +#define HEAD "\0034[DNS]\017\t" + +#define PIPE_READ 0 +#define PIPE_WRITE 1 +#define MAX_HOSTNAME 128 + +static xchat_plugin *ph; +static thread *active_thread = NULL; + + +static int +waitline (void *source, char *buf, int bufsize) +{ + int i = 0; + int len; + + while(1) + { + len = 1; + /* we can't read() here, due to glib's giowin32 */ + if(ph->xchat_read_fd(ph, source, buf + i, &len) != 0) + return -1; + if(buf[i] == '\n' || bufsize == i + 1) + { + buf[i] = 0; + return i; + } + i++; + } +} + +static void * +thread_function (void *ud) +{ +#ifdef IPV6 + struct addrinfo *ent; + struct addrinfo *cur; + struct addrinfo hints; +#else + struct hostent *ent; +#endif + thread *th = ud; + int fd = th->pipe_fd[PIPE_WRITE]; + int ret; + char ipstring[MAX_HOSTNAME]; + char reverse[MAX_HOSTNAME]; +// int i; + + active_thread = th; + +#ifdef IPV6 + memset (&hints, 0, sizeof (hints)); + hints.ai_family = PF_UNSPEC; /* support ipv6 and ipv4 */ + hints.ai_flags = AI_CANONNAME; +// hints.ai_socktype = SOCK_STREAM; + + ret = getaddrinfo (th->userdata, NULL, &hints, &ent); + if (ret != 0) + { + sprintf (ipstring, "1%d\n", ret); /* failed */ + write (fd, ipstring, strlen (ipstring)); +// Sleep (3000); + active_thread = NULL; + return 0; + } + +// i = 0; + cur = ent; + while (cur) + { + /* find the numeric IP number */ + ipstring[0] = 0; + getnameinfo (cur->ai_addr, cur->ai_addrlen, + ipstring, sizeof (ipstring), NULL, 0, NI_NUMERICHOST); + + if (cur->ai_canonname) + { + /* force reverse lookup if canonname & ipstring are the same */ + if (/*i == 0 &&*/ strcmp (cur->ai_canonname, ipstring) == 0) + goto lamecode; + } + + if (cur->ai_canonname) + { + write (fd, "0", 1); + write (fd, ipstring, strlen (ipstring)); + write (fd, "\n", 1); + write (fd, cur->ai_canonname, strlen (cur->ai_canonname)); + } else + { +lamecode: + // ret = 1; + // if (i == 0) + { + /* reverse lookup */ + reverse[0] = 0; + ret = getnameinfo (cur->ai_addr, cur->ai_addrlen, + reverse, sizeof (reverse), NULL, 0, NI_NAMEREQD); + } + + write (fd, "0", 1); + write (fd, ipstring, strlen (ipstring)); + + write (fd, "\n", 1); + if (ret == 0) + write (fd, reverse, strlen (reverse)); + } + write (fd, "\n", 1); + +// i++; + cur = cur->ai_next; + } + + /* tell the parent we're done */ + write (fd, "2\n", 2); + freeaddrinfo (ent); + +#else + ent = gethostbyname (th->userdata); + if (ent) + { + write (fd, "0", 1); + write (fd, ent->h_name, strlen (ent->h_name)); + write (fd, "\n", 1); + write (fd, ent->h_name, strlen (ent->h_name)); + write (fd, "\n", 1); + write (fd, "2\n", 2); + } else + { + write (fd, "10\n", 1); + } +#endif + +// Sleep (3000); + active_thread = NULL; /* race condition, better than nothing */ + + return 0; +} + +static int +dns_close_pipe (int fd) +{ + close (fd); + return 0; +} + +/* read messages comming from the child (through the pipe) */ + +static int +dns_read_cb (int fd, int flags, thread *th, void *source) +{ + char buf[512]; + char buf2[512]; + + while (waitline (source, buf, sizeof (buf))) + { + switch (buf[0]) + { + case '0': /* got data to show */ + waitline (source, buf2, sizeof (buf2)); + if (buf2[0] == 0) + xchat_printf(ph, HEAD"\002Numerical\002: %s\n", buf + 1); + else + xchat_printf(ph, HEAD"\002Canonical\002: %s \002Numerical\002: %s\n", buf2, buf + 1); + return 1; + + case '1': /* failed */ + xchat_printf(ph, HEAD"Lookup failed. %s\n", gai_strerrorA (atoi (buf + 1))); + + case '2': /* done */ + // close (th->pipe_fd[PIPE_WRITE]); + // close (th->pipe_fd[PIPE_READ]); + xchat_hook_timer(ph, 3000, dns_close_pipe, (void *)th->pipe_fd[PIPE_WRITE]); + xchat_hook_timer(ph, 4000, dns_close_pipe, (void *)th->pipe_fd[PIPE_READ]); + free (th->userdata); /* hostname strdup'ed */ + free (th); + return 0; + } + } + + return 1; +} + +/* find hostname from nickname (search the userlist, current chan only) */ + +static char * +find_nick_host (char *nick) +{ + xchat_list *list; + char *at; + const char *host; + + list = xchat_list_get (ph, "users"); + if (!list) + return NULL; + + while (xchat_list_next (ph, list)) + { + if (stricmp (nick, xchat_list_str (ph, list, "nick")) == 0) + { + host = xchat_list_str (ph, list, "host"); + if (host) + { + at = strrchr (host, '@'); + if (at) + return at + 1; + } + break; + } + } + + return NULL; +} + +static int +dns_cmd_cb (char *word[], char *word_eol[], void *ud) +{ + thread *th; + char *nickhost; + + if (!word[2][0]) + { + xchat_print (ph, HELP); + return XCHAT_EAT_ALL; + } + + th = thread_new (); + if (th) + { + nickhost = find_nick_host (word[2]); + if (nickhost) + { + xchat_printf (ph, HEAD"Looking up %s (%s)...\n", nickhost, word[2]); + th->userdata = strdup (nickhost); + } else + { + xchat_printf (ph, HEAD"Looking up %s...\n", word[2]); + th->userdata = strdup (word[2]); + } + + if (thread_start (th, thread_function, th)) + { + xchat_hook_fd(ph, th->pipe_fd[PIPE_READ], + XCHAT_FD_READ | XCHAT_FD_EXCEPTION | XCHAT_FD_NOTSOCKET, + (void *)dns_read_cb, th); + + } + } + + return XCHAT_EAT_ALL; +} + +int +xchat_plugin_deinit (xchat_plugin *plugin_handle) +{ + while (active_thread) /* children will set this var to NULL soon... */ + { + Sleep (1000); + } + return 1; +} + +int +#ifdef STATIC +exec_plugin_init +#else +xchat_plugin_init +#endif + (xchat_plugin *plugin_handle, char **plugin_name, + char **plugin_desc, char **plugin_version, char *arg) +{ + /* we need to save this for use with any xchat_* functions */ + ph = plugin_handle; + + /*if((void *)ph->xchat_read_fd == ph->dummy7) + { + xchat_print(ph, HEAD"This version of xchat is too old.\n"); + return 0; + }*/ + + *plugin_name = "DNS"; + *plugin_desc = "Threaded IPv4/6 DNS Command"; + *plugin_version = DNS_VERSION; + + xchat_hook_command(ph, "DNS", XCHAT_PRI_LOW, dns_cmd_cb, HELP, 0); + + return 1; /* return 1 for success */ +} diff --git a/plugins/dns/thread.c b/plugins/dns/thread.c new file mode 100644 index 00000000..aa153137 --- /dev/null +++ b/plugins/dns/thread.c @@ -0,0 +1,111 @@ +#include <stdlib.h> + +#define USE_PTHREAD + +#ifdef WIN32 + +#include <windows.h> +#define pthread_t DWORD +#define pipe(a) _pipe(a,4096,_O_BINARY) + +#else +#ifdef USE_PTHREAD + +#include <pthread.h> + +#else + +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#define pthread_t int + +#endif +#endif + + +typedef struct +{ + pthread_t threadid; + int pipe_fd[2]; + void *userdata; +} thread; + +thread * +thread_new (void) +{ + thread *th; + + th = calloc (1, sizeof (*th)); + if (!th) + return NULL; + + if (pipe (th->pipe_fd) == -1) + { + free (th); + return NULL; + } + +#ifdef __EMX__ /* os/2 */ + setmode (pipe_fd[0], O_BINARY); + setmode (pipe_fd[1], O_BINARY); +#endif + + return th; +} + +int +thread_start (thread *th, void *(*start_routine)(void *), void *arg) +{ + pthread_t id; + +#ifdef WIN32 + CloseHandle (CreateThread (NULL, 0, + (LPTHREAD_START_ROUTINE)start_routine, + arg, 0, (DWORD *)&id)); +#else +#ifdef USE_PTHREAD + if (pthread_create (&id, NULL, start_routine, arg) != 0) + return 0; +#else + switch (id = fork ()) + { + case -1: + return 0; + case 0: + /* this is the child */ + setuid (getuid ()); + start_routine (arg); + _exit (0); + } +#endif +#endif + + th->threadid = id; + + return 1; +} + +/*void +thread_kill (thread *th) +{ +#ifdef WIN32 + PostThreadMessage (th->threadid, WM_QUIT, 0, 0); +#else +#ifdef USE_PTHREAD + pthread_cancel (th->threadid); + pthread_join (th->threadid, (void *)&th); +#else + kill (th->threadid, SIGKILL); + waitpid (th->threadid, NULL, 0); +#endif +#endif +} + +void +thread_free (thread *th) +{ + close (th->pipe_fd[0]); + close (th->pipe_fd[1]); + free (th); +}*/ |