From bfee90f11c9766808a0c7decccc3289d4764019f Mon Sep 17 00:00:00 2001 From: Berke Viktor Date: Fri, 20 Jan 2012 05:43:13 +0100 Subject: add DNS plugin --- plugins/dns/dns.c | 329 +++++++++++++++++++++++++++++++++++++++++++ plugins/dns/makefile.mak | 22 +++ plugins/dns/thread.c | 33 +++++ plugins/dns/thread.h | 11 ++ plugins/makefile.mak | 4 + win32/release-x64.bat | 1 + win32/release-x86.bat | 1 + win32/xchat-wdk-x64.skel.iss | 2 + win32/xchat-wdk-x86.skel.iss | 2 + 9 files changed, 405 insertions(+) create mode 100644 plugins/dns/dns.c create mode 100644 plugins/dns/makefile.mak create mode 100644 plugins/dns/thread.c create mode 100644 plugins/dns/thread.h diff --git a/plugins/dns/dns.c b/plugins/dns/dns.c new file mode 100644 index 00000000..2bf58195 --- /dev/null +++ b/plugins/dns/dns.c @@ -0,0 +1,329 @@ +/* XChat Win32 DNS Plugin + * Copyright (C) 2003-2004 Peter Zelezny. + * Copyright (C) 2012 Berke Viktor. + * + * 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 +#include +#include +#include + +#define USE_IPV6 + +#ifdef WIN32 +#ifdef USE_IPV6 +#include +#include +#else +#include +#endif +#else +#include +#include +#include +#endif + +#include "xchat-plugin.h" +#include "thread.h" + +#define HELP "Usage: DNS \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 USE_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 USE_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); + } + xchat_printf (ph, "DNS plugin unloaded\n"); + return 1; +} + +int +xchat_plugin_init + (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; + + *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); + xchat_printf (ph, "DNS plugin loaded\n"); + + return 1; /* return 1 for success */ +} diff --git a/plugins/dns/makefile.mak b/plugins/dns/makefile.mak new file mode 100644 index 00000000..384e6be1 --- /dev/null +++ b/plugins/dns/makefile.mak @@ -0,0 +1,22 @@ +include "..\..\src\makeinc.mak" + +DNS_OBJECTS = \ +dns.obj \ +thread.obj + +all: $(DNS_OBJECTS) dns.def + link $(LDFLAGS) $(LIBS) /dll /out:xcdns.dll /def:dns.def $(DNS_OBJECTS) + +dns.def: + echo EXPORTS > dns.def + echo xchat_plugin_init >> dns.def + echo xchat_plugin_deinit >> dns.def + +.c.obj: + $(CC) $(CFLAGS) $(GLIB) /I.. /c $< + +clean: + del *.obj + del *.dll + del *.exp + del *.lib diff --git a/plugins/dns/thread.c b/plugins/dns/thread.c new file mode 100644 index 00000000..02b17cfb --- /dev/null +++ b/plugins/dns/thread.c @@ -0,0 +1,33 @@ +#include +#include "thread.h" + +thread * +thread_new (void) +{ + thread *th; + + th = calloc (1, sizeof (*th)); + if (!th) + { + return NULL; + } + + if (_pipe (th->pipe_fd, 4096, _O_BINARY) == -1) + { + free (th); + return NULL; + } + + return th; +} + +int +thread_start (thread *th, void *(*start_routine)(void *), void *arg) +{ + DWORD id; + + CloseHandle (CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, arg, 0, (DWORD *)&id)); + th->threadid = id; + + return 1; +} diff --git a/plugins/dns/thread.h b/plugins/dns/thread.h new file mode 100644 index 00000000..1ec6932d --- /dev/null +++ b/plugins/dns/thread.h @@ -0,0 +1,11 @@ +#include + +typedef struct +{ + DWORD threadid; + int pipe_fd[2]; + void *userdata; +} thread; + +thread *thread_new (void); +int thread_start (thread *th, void *(*start_routine)(void *), void *arg); diff --git a/plugins/makefile.mak b/plugins/makefile.mak index 07205ab4..19b3cb75 100644 --- a/plugins/makefile.mak +++ b/plugins/makefile.mak @@ -3,6 +3,8 @@ all: @-$(MAKE) /nologo /s /f makefile.mak $@ @cd ..\gtkpref @-$(MAKE) /nologo /s /f makefile.mak $@ + @cd ..\dns + @-$(MAKE) /nologo /s /f makefile.mak $@ @cd ..\doat @-$(MAKE) /nologo /s /f makefile.mak $@ @cd ..\exec @@ -37,6 +39,8 @@ clean: @-$(MAKE) /nologo /s /f makefile.mak clean $@ @cd ..\gtkpref @-$(MAKE) /nologo /s /f makefile.mak clean $@ + @cd ..\dns + @-$(MAKE) /nologo /s /f makefile.mak clean $@ @cd ..\doat @-$(MAKE) /nologo /s /f makefile.mak clean $@ @cd ..\exec diff --git a/win32/release-x64.bat b/win32/release-x64.bat index 1b3c2586..8437f525 100644 --- a/win32/release-x64.bat +++ b/win32/release-x64.bat @@ -56,6 +56,7 @@ copy %DEPS_ROOT%\bin\cert.pem %XCHAT_DEST% copy %DEPS_ROOT%\bin\libenchant.dll %XCHAT_DEST% xcopy /q /s /i %DEPS_ROOT%\lib\enchant\libenchant_myspell.dll %XCHAT_DEST%\lib\enchant\ xcopy /q /s /i ..\plugins\checksum\xcchecksum.dll %XCHAT_DEST%\plugins\ +copy ..\plugins\dns\xcdns.dll %XCHAT_DEST%\plugins copy ..\plugins\doat\xcdoat.dll %XCHAT_DEST%\plugins copy ..\plugins\exec\xcexec.dll %XCHAT_DEST%\plugins copy ..\plugins\fishlim\xcfishlim.dll %XCHAT_DEST%\plugins diff --git a/win32/release-x86.bat b/win32/release-x86.bat index 4583add6..dc022b75 100644 --- a/win32/release-x86.bat +++ b/win32/release-x86.bat @@ -58,6 +58,7 @@ copy %DEPS_ROOT%\bin\cert.pem %XCHAT_DEST% copy %DEPS_ROOT%\bin\libenchant.dll %XCHAT_DEST% xcopy /q /s /i %DEPS_ROOT%\lib\enchant\libenchant_myspell.dll %XCHAT_DEST%\lib\enchant\ xcopy /q /s /i ..\plugins\checksum\xcchecksum.dll %XCHAT_DEST%\plugins\ +copy ..\plugins\dns\xcdns.dll %XCHAT_DEST%\plugins copy ..\plugins\doat\xcdoat.dll %XCHAT_DEST%\plugins copy ..\plugins\exec\xcexec.dll %XCHAT_DEST%\plugins copy ..\plugins\fishlim\xcfishlim.dll %XCHAT_DEST%\plugins diff --git a/win32/xchat-wdk-x64.skel.iss b/win32/xchat-wdk-x64.skel.iss index 955eeb42..1caf8198 100644 --- a/win32/xchat-wdk-x64.skel.iss +++ b/win32/xchat-wdk-x64.skel.iss @@ -35,6 +35,7 @@ Name: "translations"; Description: "Translations"; Types: normal full custom; Fl ;Name: "spelling"; Description: "Spelling Dictionaries"; Types: full custom; Flags: disablenouninstallwarning Name: "plugins"; Description: "Plugins"; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\checksum"; Description: "Checksum"; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\dns"; Description: "DNS"; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\doat"; Description: "Do At"; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\exec"; Description: "Exec"; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\fishlim"; Description: "FiSHLiM"; Types: full custom; Flags: disablenouninstallwarning @@ -150,6 +151,7 @@ Source: "lib\gtk-2.0\modules\libgail.dll"; DestDir: "{app}\lib\gtk-2.0\modules"; ;obs Source: "gtk2-prefs.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: gtkengines Source: "plugins\xcchecksum.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: plugins\checksum +Source: "plugins\xcdns.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: plugins\dns Source: "plugins\xcdoat.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: plugins\doat Source: "plugins\xcexec.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: plugins\exec Source: "plugins\xcfishlim.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: plugins\fishlim diff --git a/win32/xchat-wdk-x86.skel.iss b/win32/xchat-wdk-x86.skel.iss index dbc75f80..a53e7cfd 100644 --- a/win32/xchat-wdk-x86.skel.iss +++ b/win32/xchat-wdk-x86.skel.iss @@ -34,6 +34,7 @@ Name: "translations"; Description: "Translations"; Types: normal full custom; Fl ;Name: "spelling"; Description: "Spelling Dictionaries"; Types: full custom; Flags: disablenouninstallwarning Name: "plugins"; Description: "Plugins"; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\checksum"; Description: "Checksum"; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\dns"; Description: "DNS"; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\doat"; Description: "Do At"; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\exec"; Description: "Exec"; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\fishlim"; Description: "FiSHLiM"; Types: full custom; Flags: disablenouninstallwarning @@ -151,6 +152,7 @@ Source: "lib\gtk-2.0\modules\libgail.dll"; DestDir: "{app}\lib\gtk-2.0\modules"; ;obs Source: "gtk2-prefs.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: gtkengines Source: "plugins\xcchecksum.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: plugins\checksum +Source: "plugins\xcdns.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: plugins\dns Source: "plugins\xcdoat.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: plugins\doat Source: "plugins\xcexec.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: plugins\exec Source: "plugins\xcfishlim.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: plugins\fishlim -- cgit 1.4.1