├── .gitignore ├── AUTHORS ├── COPYING ├── Makefile ├── README ├── TODO ├── VERSION ├── completions └── zsh │ └── _proxychains4 ├── configure ├── src ├── allocator_thread.c ├── allocator_thread.h ├── common.c ├── common.h ├── core.c ├── core.h ├── daemon │ ├── daemon.c │ ├── hsearch.c │ ├── hsearch.h │ ├── sblist.c │ ├── sblist.h │ ├── sblist_delete.c │ ├── udpclient.c │ ├── udpserver.c │ └── udpserver.h ├── debug.c ├── debug.h ├── hash.c ├── hash.h ├── hostsreader.c ├── ip_type.h ├── libproxychains.c ├── main.c ├── mutex.h ├── proxychains.conf ├── proxyresolv ├── rdns.c ├── rdns.h ├── remotedns.h └── version.c ├── tests ├── test_getaddrinfo.c ├── test_gethostbyname.c ├── test_gethostent.c ├── test_gethostent_r.c ├── test_getnameinfo.c ├── test_proxy_gethostbyname.c ├── test_sendto.c ├── test_shm.c └── test_v4_in_v6.c └── tools ├── install.sh └── version.sh /.gitignore: -------------------------------------------------------------------------------- 1 | proxychains4 2 | proxychains4-daemon 3 | *.bz2 4 | *.xz 5 | *.o 6 | *.so 7 | *.la 8 | *.lo 9 | .deps/ 10 | .libs/ 11 | *.rcb 12 | *.out 13 | *~ 14 | *.patch 15 | version.h 16 | 17 | # Autoconf stuff 18 | libtool 19 | config.* 20 | stamp-h 21 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | original code up to version 3.1 2 | N3E7CR34TUR3. 3 | http://proxychains.sourceforge.net 4 | netcreature@users.sourceforge.net 5 | 6 | main.c, remote-dns, thread safety, bugfixes, build system, 7 | cleanups, mac support 8 | rofl0r. 9 | https://github.com/rofl0r/proxychains-ng 10 | 11 | localnet, bugfixes 12 | jianing yang. 13 | https://github.com/jianingy/proxychains 14 | https://sourceforge.net/projects/proxychains/forums/forum/644747/topic/3498696 15 | 16 | round-robin 17 | crass. 18 | https://github.com/crass/proxychains-ng 19 | 20 | poll_retry (fixes for signal handling) 21 | colin cross. 22 | https://sourceforge.net/projects/proxychains/forums/forum/644747/topic/2367923 23 | 24 | collecting patches from px forum and putting it into a repo 25 | adam hamsik. 26 | https://github.com/haad/proxychains 27 | 28 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile for proxychains (requires GNU make), stolen from musl 3 | # 4 | # Use config.mak to override any of the following variables. 5 | # Do not make changes here. 6 | # 7 | 8 | exec_prefix = /usr/local 9 | bindir = $(exec_prefix)/bin 10 | 11 | prefix = /usr/local/ 12 | includedir = $(prefix)/include 13 | libdir = $(prefix)/lib 14 | sysconfdir = $(prefix)/etc 15 | zshcompletiondir = $(prefix)/share/zsh/site-functions 16 | 17 | OBJS = src/common.o src/main.o 18 | 19 | DOBJS = src/daemon/hsearch.o \ 20 | src/daemon/sblist.o src/daemon/sblist_delete.o \ 21 | src/daemon/daemon.o src/daemon/udpserver.o 22 | 23 | LOBJS = src/version.o \ 24 | src/core.o src/common.o src/libproxychains.o \ 25 | src/allocator_thread.o src/rdns.o \ 26 | src/hostsreader.o src/hash.o src/debug.o 27 | 28 | 29 | GENH = src/version.h 30 | 31 | CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe 32 | NO_AS_NEEDED = -Wl,--no-as-needed 33 | LDFLAGS = -fPIC $(NO_AS_NEEDED) $(LIBDL) $(PTHREAD) 34 | INC = 35 | PIC = -fPIC 36 | AR = $(CROSS_COMPILE)ar 37 | RANLIB = $(CROSS_COMPILE)ranlib 38 | SOCKET_LIBS = 39 | 40 | LDSO_SUFFIX = so 41 | LD_SET_SONAME = -Wl,-soname= 42 | INSTALL = ./tools/install.sh 43 | 44 | LDSO_PATHNAME = libproxychains4.$(LDSO_SUFFIX) 45 | 46 | SHARED_LIBS = $(LDSO_PATHNAME) 47 | ALL_LIBS = $(SHARED_LIBS) 48 | PXCHAINS = proxychains4 49 | PXCHAINS_D = proxychains4-daemon 50 | ALL_TOOLS = $(PXCHAINS) $(PXCHAINS_D) 51 | ALL_CONFIGS = src/proxychains.conf 52 | ZSH_COMPLETION = completions/zsh/_proxychains4 53 | 54 | -include config.mak 55 | 56 | CFLAGS+=$(USER_CFLAGS) $(MAC_CFLAGS) 57 | CFLAGS_MAIN=-DLIB_DIR=\"$(libdir)\" -DSYSCONFDIR=\"$(sysconfdir)\" -DDLL_NAME=\"$(LDSO_PATHNAME)\" 58 | 59 | 60 | all: $(ALL_LIBS) $(ALL_TOOLS) 61 | 62 | install: install-libs install-tools 63 | 64 | $(DESTDIR)$(bindir)/%: % 65 | $(INSTALL) -D -m 755 $< $@ 66 | 67 | $(DESTDIR)$(libdir)/%: % 68 | $(INSTALL) -D -m 644 $< $@ 69 | 70 | $(DESTDIR)$(sysconfdir)/%: src/% 71 | $(INSTALL) -D -m 644 $< $@ 72 | 73 | $(DESTDIR)$(zshcompletiondir)/%: completions/zsh/% 74 | $(INSTALL) -D -m 644 $< $@ 75 | 76 | install-libs: $(ALL_LIBS:%=$(DESTDIR)$(libdir)/%) 77 | install-tools: $(ALL_TOOLS:%=$(DESTDIR)$(bindir)/%) 78 | install-config: $(ALL_CONFIGS:src/%=$(DESTDIR)$(sysconfdir)/%) 79 | install-zsh-completion: $(ZSH_COMPLETION:completions/zsh/%=$(DESTDIR)$(zshcompletiondir)/%) 80 | 81 | clean: 82 | rm -f $(ALL_LIBS) 83 | rm -f $(ALL_TOOLS) 84 | rm -f $(OBJS) $(LOBJS) $(DOBJS) 85 | rm -f $(GENH) 86 | 87 | src/version.h: $(wildcard VERSION .git) 88 | printf '#define VERSION "%s"\n' "$$(sh tools/version.sh)" > $@ 89 | 90 | src/version.o: src/version.h 91 | 92 | %.o: %.c 93 | $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_MAIN) $(INC) $(PIC) -c -o $@ $< 94 | 95 | $(LDSO_PATHNAME): $(LOBJS) 96 | $(CC) $(LDFLAGS) $(FAT_LDFLAGS) $(LD_SET_SONAME)$(LDSO_PATHNAME) \ 97 | $(USER_LDFLAGS) -shared -o $@ $^ $(SOCKET_LIBS) 98 | 99 | $(PXCHAINS): $(OBJS) 100 | $(CC) $^ $(FAT_BIN_LDFLAGS) $(USER_LDFLAGS) $(LIBDL) -o $@ 101 | 102 | $(PXCHAINS_D): $(DOBJS) 103 | $(CC) $^ $(FAT_BIN_LDFLAGS) $(USER_LDFLAGS) -o $@ 104 | 105 | 106 | .PHONY: all clean install install-config install-libs install-tools install-zsh-completion 107 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ProxyChains-NG ver 4.17 README 2 | ============================= 3 | 4 | ProxyChains is a UNIX program, that hooks network-related libc functions 5 | in DYNAMICALLY LINKED programs via a preloaded DLL (dlsym(), LD_PRELOAD) 6 | and redirects the connections through SOCKS4a/5 or HTTP proxies. 7 | It supports TCP only (no UDP/ICMP etc). 8 | 9 | The way it works is basically a HACK; so it is possible that it doesn't 10 | work with your program, especially when it's a script, or starts 11 | numerous processes like background daemons or uses dlopen() to load 12 | "modules" (bug in glibc dynlinker). 13 | It should work with simple compiled (C/C++) dynamically linked programs 14 | though. 15 | 16 | If your program doesn't work with proxychains, consider using an 17 | iptables based solution instead; this is much more robust. 18 | 19 | Supported Platforms: Linux, BSD, Mac, Haiku. 20 | 21 | 22 | *********** ATTENTION *********** 23 | 24 | this program can be used to circumvent censorship. 25 | doing so can be VERY DANGEROUS in certain countries. 26 | 27 | ALWAYS MAKE SURE THAT PROXYCHAINS WORKS AS EXPECTED 28 | BEFORE USING IT FOR ANYTHING SERIOUS. 29 | 30 | this involves both the program and the proxy that you're going to 31 | use. 32 | 33 | for example, you can connect to some "what is my ip" service 34 | like ifconfig.me to make sure that it's not using your real ip. 35 | 36 | ONLY USE PROXYCHAINS IF YOU KNOW WHAT YOU'RE DOING. 37 | 38 | THE AUTHORS AND MAINTAINERS OF PROXYCHAINS DO NOT TAKE ANY 39 | RESPONSIBILITY FOR ANY ABUSE OR MISUSE OF THIS SOFTWARE AND 40 | THE RESULTING CONSEQUENCES. 41 | 42 | *** Installation *** 43 | 44 | # needs a working C compiler, preferably gcc 45 | ./configure --prefix=/usr --sysconfdir=/etc 46 | make 47 | [optional] sudo make install 48 | [optional] sudo make install-config (installs proxychains.conf) 49 | 50 | if you dont install, you can use proxychains from the build directory 51 | like this: ./proxychains4 -f src/proxychains.conf telnet google.com 80 52 | 53 | Changelog: 54 | ---------- 55 | Version 4.17 56 | - add hook for close_range function, fixing newer versions of openssh 57 | - fat-binary-m1 option for mac 58 | - fix DNS error handling in proxy_dns_old 59 | - simplify init code 60 | - fix openbsd preloading 61 | - fix double-close in multithreaded apps 62 | - various improvements to configure script 63 | 64 | Version 4.16 65 | - fix regression in configure script linker flag detection 66 | - remove 10 year old workaround for wrong glibc getnameinfo signature 67 | - support for new DYLD hooking method for OSX Monterey 68 | - netbsd compilation fix 69 | - support IPv6 localnets 70 | - more user-friendly error message when execvp fails 71 | - proxy_getaddrinfo(): fill in ai_socktype if requested 72 | 73 | Version 4.15 74 | - fix configure script for buggy binutils version 75 | - initialize rand_seed with nano-second granularity 76 | - add support for numeric ipv6 in getaddrinfo 77 | - fix bug in getaddrinfo when node is null and !passive 78 | - add dnat feature 79 | - add raw proxy type 80 | - add haiku support 81 | - add proxy_dns_old to emulate proxychains 3.1 behaviour 82 | - add new proxy_dns_daemon feature (experimental) 83 | - various other fixes 84 | 85 | Version 4.14 86 | - allow alternative proto://user:pass@ip:port syntax for proxylist 87 | - fix endless loop in round robin mode when all proxies are down (#147) 88 | - fix compilation on android (#265) 89 | - fix fd leak in forked processes (#273) 90 | - skip connection attempt to nullrouted ips 91 | - allow hostnames for proxylist under specific circumstances 92 | 93 | Version 4.13 94 | - fix robustness of DNS lookup thread and a segfault 95 | - fix socks5 user/pass auth on non-conforming servers 96 | - fix memory leak 97 | - add support for Solaris 98 | 99 | Version 4.12 100 | - fix several build issues 101 | - for MAC 102 | - with -pie 103 | - with custom CC 104 | - compatibility fix for some GUI apps (8870140) 105 | - compatibility fix for some HTTP proxies (cf9a16d) 106 | - fix several warnings for cleaner build on debian 107 | - fix random_chain on OSX (0f6b226) 108 | 109 | Version 4.11 110 | - preliminary IPv6 support 111 | - fixed bug in hostsreader 112 | - preliminary support for usage on OpenBSD (caveat emptor) 113 | 114 | Version 4.10 115 | - fix regression in linking order with custom LDFLAGS 116 | - fix segfault in DNS mapping code in programs with > ~400 different lookups 117 | 118 | Version 4.9 119 | - fix a security issue CVE-2015-3887 120 | - add sendto hook to handle MSG_FASTOPEN flag 121 | - replace problematic hostentdb with hostsreader 122 | - fix compilation on OpenBSD (although doesn't work there) 123 | 124 | Version 4.8.1: 125 | - fix regression in 4.8 install-config Makefile target 126 | 127 | Version 4.8: 128 | - fix for odd cornercase where getaddrinfo was used with AI_NUMERICHOST 129 | to test for a numeric ip instead of resolving it (fixes nmap). 130 | - allow usage with programs that rely on LD_PRELOAD themselves 131 | - reject wrong entries in config file 132 | - print version number on startup 133 | 134 | Version 4.7: 135 | - new round_robin chaintype by crass. 136 | - fix bug with lazy allocation when GCC constructor was not used. 137 | - new configure flag --fat-binary to create a "fat" binary/library on OS X 138 | - return EBADF rather than EINTR in close hook. 139 | it's legal for a program to retry close() calls when they receive 140 | EINTR, which could cause an infinite loop, as seen in chromium. 141 | 142 | Version 4.6: 143 | - some cosmetic fixes to Makefile, fix a bug when non-numeric ip was 144 | used as proxy server address. 145 | 146 | Version 4.5: 147 | - hook close() to prevent OpenSSH from messing with internal infrastructure. 148 | this caused ssh client to segfault when proxified. 149 | 150 | Version 4.4: 151 | - FreeBSD port 152 | - fixes some installation issues on Debian and Mac. 153 | 154 | Version 4.3: 155 | - fixes programs that do dns-lookups in child processes (fork()ed), 156 | like irssi. to achieve this, support for compilation without pthreads 157 | was sacrified. 158 | - fixes thread safety for gethostent() calls. 159 | - improved DNS handling speed, since hostent db is cached. 160 | 161 | Version 4.2: 162 | - fixes compilation issues with ubuntu 12.04 toolchain 163 | - fixes segfault in rare codepath 164 | 165 | Version 4.1 166 | - support for mac os x (all archs) 167 | - all internal functions are threadsafe when compiled with -DTHREAD_SAFE 168 | (default). 169 | 170 | Version 4.0 171 | - replaced dnsresolver script (which required a dynamically linked "dig" 172 | binary to be present) with remote DNS lookup. 173 | this speeds up any operation involving DNS, as the old script had to use TCP. 174 | additionally it allows to use .onion urls when used with TOR. 175 | - removed broken autoconf build system with a simple Makefile. 176 | there's a ./configure script though for convenience. 177 | it also adds support for a config file passed via command line switches/ 178 | environment variables. 179 | 180 | Version 3.0 181 | - support for DNS resolving through proxy 182 | supports SOCKS4, SOCKS5 and HTTP CONNECT proxy servers. 183 | Auth-types: socks - "user/pass" , http - "basic". 184 | 185 | When to use it ? 186 | 1) When the only way to get "outside" from your LAN is through proxy server. 187 | 2) To get out from behind restrictive firewall which filters outgoing ports. 188 | 3) To use two (or more) proxies in chain: 189 | like: your_host <--> proxy1 <--> proxy2 <--> target_host 190 | 4) To "proxify" some program with no proxy support built-in (like telnet) 191 | 5) Access intranet from outside via proxy. 192 | 6) To use DNS behind proxy. 193 | 7) To access hidden tor onion services. 194 | 195 | Some cool features: 196 | 197 | * This program can mix different proxy types in the same chain 198 | like: your_host <-->socks5 <--> http <--> socks4 <--> target_host 199 | * Different chaining options supported 200 | random order from the list ( user defined length of chain ). 201 | exact order (as they appear in the list ) 202 | dynamic order (smart exclude dead proxies from chain) 203 | * You can use it with most TCP client applications, possibly even network 204 | scanners, as long as they use standard libc functionality. 205 | pcap based scanning does not work. 206 | * You can use it with servers, like squid, sendmail, or whatever. 207 | * DNS resolving through proxy. 208 | 209 | 210 | Configuration: 211 | -------------- 212 | 213 | proxychains looks for config file in following order: 214 | 1) file listed in environment variable PROXYCHAINS_CONF_FILE or 215 | provided as a -f argument to proxychains script or binary. 216 | 2) ./proxychains.conf 217 | 3) $(HOME)/.proxychains/proxychains.conf 218 | 4) $(sysconfdir)/proxychains.conf ** 219 | 220 | ** usually /etc/proxychains.conf 221 | 222 | Usage Example: 223 | 224 | $ proxychains telnet targethost.com 225 | 226 | in this example it will run telnet through proxy(or chained proxies) 227 | specified by proxychains.conf 228 | 229 | Usage Example: 230 | 231 | $ proxychains -f /etc/proxychains-other.conf telnet targethost2.com 232 | 233 | in this example it will use different configuration file then proxychains.conf 234 | to connect to targethost2.com host. 235 | 236 | Usage Example: 237 | 238 | $ proxyresolv targethost.com 239 | 240 | in this example it will resolve targethost.com through proxy(or chained proxies) 241 | specified by proxychains.conf 242 | 243 | Known Problems: 244 | --------------- 245 | - newer versions of nmap try to determine the network interface to use 246 | even if it's not needed (like when doing simple syn scans which use the 247 | standard POSIX socket API. this results in errors when proxychains hands 248 | out an ip address to a reserved address space. 249 | possible workarounds: disable proxy_dns, use a numeric ip, or use nmap's 250 | native support for SOCKS proxies. 251 | 252 | - Mac OS X 10.11 (El Capitan) ships with a new security feature called SIP 253 | that prevents hooking of system apps. 254 | workarounds are to partially disable SIP by issuing 255 | csrutil enable --without debug in recovery mode, 256 | or to copy the system binary into the home directory and run it from there. 257 | see github issue #78 for details. 258 | 259 | - the glibc dynlinker has a bug or security feature that inhibits dlopen()ed 260 | modules from being subject to the same dlsym hooks as installed for the main 261 | program. this mainly affects scripting languages such as perl or python 262 | that heavily rely on dlopen() for modules written in C to work. 263 | there are unconfirmed reports that it works as root though. 264 | musl libc is unaffected from the bug. 265 | 266 | 267 | Community: 268 | ---------- 269 | #proxychains on irc.libera.chat 270 | 271 | Donations: 272 | ---------- 273 | bitcoins donations are welcome - please send to this address: 274 | 1C9LBpuy56veBqw5N33sZMoZW8mwCw3tPh 275 | 276 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | ProxyChains ver 4.0 TODO 2 | =================== 3 | 4 | 5 | hooks for reentrant dns functions, i.e. gethostbyaddr_r 6 | 7 | 8 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 4.17 2 | -------------------------------------------------------------------------------- /completions/zsh/_proxychains4: -------------------------------------------------------------------------------- 1 | #compdef proxychains4 2 | 3 | _arguments \ 4 | '(- : *)--help[More help in README file]' \ 5 | '-q[makes proxychains quiet - this overrides the config setting]' \ 6 | '-f[allows one to manually specify a configfile to use]: :_files' \ 7 | '(-)1: :{_command_names -e}' \ 8 | '*:: :_normal' 9 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | prefix=/usr/local 4 | OUR_CPPFLAGS= 5 | 6 | # Get a temporary filename 7 | fail() { printf "%s\n" "$1" >&2 ; exit 1 ; } 8 | i=0 9 | set -C 10 | while : ; do i=$(($i+1)) 11 | tmpc="./conf$$-$PPID-$i.c" 12 | 2>|/dev/null > "$tmpc" && break 13 | test "$i" -gt 50 && fail "$0: cannot create temporary file $tmpc" 14 | done 15 | set +C 16 | trap 'rm "$tmpc"' EXIT INT QUIT TERM HUP 17 | 18 | check_compile() { 19 | printf "checking %s ... " "$1" 20 | printf "$3" > "$tmpc" 21 | local res=0 22 | $CC $OUR_CPPFLAGS $CPPFLAGS $2 $CFLAGS "$tmpc" -o "$tmpc".out >/dev/null 2>&1 \ 23 | || res=1 24 | test x$res = x0 && \ 25 | { printf "yes\n" ; test x"$2" = x || OUR_CPPFLAGS="$OUR_CPPFLAGS $2" ; } \ 26 | || printf "no\n" 27 | rm -f "$tmpc".out 28 | return $res 29 | } 30 | 31 | get_define() { 32 | $CC $OUR_CPPFLAGS $CPPFLAGS $CFLAGS -dM -E - /dev/null && res=0 45 | test x$res = x0 && printf "yes\n" || printf "no\n" 46 | return $res 47 | } 48 | 49 | check_compile_run() { 50 | printf "checking %s ... " "$1" 51 | printf "$2" > "$tmpc" 52 | local res=0 53 | $CC $OUR_CPPFLAGS $CPPFLAGS $CFLAGS "$tmpc" -o "$tmpc".out >/dev/null 2>&1 \ 54 | || res=1 55 | test x$res = x0 && { "$tmpc".out || res=1 ; } 56 | rm -f "$tmpc".out 57 | test x$res = x0 && printf "yes\n" || printf "no\n" 58 | return $res 59 | } 60 | 61 | check_link_silent() { 62 | printf "$2" > "$tmpc" 63 | local res=0 64 | $CC $OUR_CPPFLAGS $CPPFLAGS $1 $CFLAGS "$tmpc" -o "$tmpc".out >/dev/null 2>&1 || res=1 65 | rm -f "$tmpc".out 66 | return $res 67 | } 68 | 69 | check_link() { 70 | printf "checking %s ... " "$1" 71 | local res=0 72 | check_link_silent "$2" "$3" || res=1 73 | test x$res = x0 && printf "yes\n" || printf "no\n" 74 | return $res 75 | } 76 | 77 | usage() { 78 | echo "supported arguments" 79 | echo "--prefix=/path default: $prefix" 80 | echo "--exec_prefix=/path default: $prefix/bin" 81 | echo "--bindir=/path default: $prefix/bin" 82 | echo "--libdir=/path default: $prefix/lib" 83 | echo "--includedir=/path default: $prefix/include" 84 | echo "--sysconfdir=/path default: $prefix/etc" 85 | echo "--ignore-cve default: no" 86 | echo " if set to yes ignores CVE-2015-3887 and makes it possible" 87 | echo " to preload from current dir (possibly insecure, but handy)" 88 | echo "--fat-binary : build for both i386 and x86_64 architectures on 64-bit Macs" 89 | echo "--fat-binary-m1 : build for both arm64e and x86_64 architectures on M1 Macs" 90 | echo "--fat-binary-m2 : build for arm64, arm64e and x86_64 architectures on M2+ Macs" 91 | echo "--hookmethod=dlsym|dyld hook method for osx. default: auto" 92 | echo " if OSX >= 12 is detected, dyld method will be used if auto." 93 | echo "--help : show this text" 94 | exit 1 95 | } 96 | 97 | spliteq() { 98 | arg=$1 99 | echo "${arg#*=}" 100 | #alternatives echo "$arg" | cut -d= -f2- 101 | # or echo "$arg" | sed 's/[^=]*=//' 102 | } 103 | 104 | fat_binary= 105 | fat_binary_m1= 106 | fat_binary_m2= 107 | ignore_cve=no 108 | hookmethod=auto 109 | 110 | parsearg() { 111 | case "$1" in 112 | --prefix=*) prefix=`spliteq $1`;; 113 | --exec_prefix=*) exec_prefix=`spliteq $1`;; 114 | --bindir=*) bindir=`spliteq $1`;; 115 | --libdir=*) libdir=`spliteq $1`;; 116 | --includedir=*) includedir=`spliteq $1`;; 117 | --sysconfdir=*) sysconfdir=`spliteq $1`;; 118 | --ignore-cve) ignore_cve=1;; 119 | --ignore-cve=*) ignore_cve=`spliteq $1`;; 120 | --hookmethod=*) hookmethod=`spliteq $1`;; 121 | --fat-binary) fat_binary=1;; 122 | --fat-binary-m1) fat_binary_m1=1;; 123 | --fat-binary-m2) fat_binary_m2=1;; 124 | --help) usage;; 125 | esac 126 | } 127 | 128 | while true ; do 129 | case $1 in 130 | -*) parsearg "$1"; shift;; 131 | *) break ;; 132 | esac 133 | done 134 | 135 | if [ -z "$exec_prefix" ] ; then 136 | exec_prefix=$prefix 137 | fi 138 | 139 | if [ -z "$libdir" ] ; then 140 | libdir=$prefix/lib 141 | fi 142 | 143 | if [ -z "$includedir" ] ; then 144 | includedir=$prefix/include 145 | fi 146 | 147 | if [ -z "$sysconfdir" ] ; then 148 | sysconfdir=$prefix/etc 149 | fi 150 | 151 | if [ -z "$bindir" ] ; then 152 | bindir=$exec_prefix/bin 153 | fi 154 | 155 | if [ -z "$CC" ] ; then 156 | CC=cc 157 | fi 158 | 159 | echo > config.mak 160 | 161 | bsd_detected=false 162 | isbsd() { 163 | $bsd_detected 164 | } 165 | mac_detected=false 166 | ismac() { 167 | $mac_detected 168 | } 169 | mac_64=false 170 | ismac64() { 171 | $mac_64 172 | } 173 | solaris_detected=false 174 | issolaris() { 175 | $solaris_detected 176 | } 177 | haiku_detected=false 178 | ishaiku() { 179 | $haiku_detected 180 | } 181 | 182 | check_compile 'whether C compiler works' '' 'int main() {return 0;}' || fail 'error: install a C compiler and library' 183 | check_compile 'whether libc headers are complete' '' '#include \nint main() {return 0;}' || fail 'error: necessary libc headers are not installed' 184 | check_compile 'whether C compiler understands -Wno-unknown-pragmas' '-Wno-unknown-pragmas' 'int main() {return 0;}' 185 | 186 | if ! check_compile 'whether getnameinfo() servlen argument is POSIX compliant (socklen_t)' "-DGN_NODELEN_T=socklen_t -DGN_SERVLEN_T=socklen_t -DGN_FLAGS_T=int" \ 187 | '#define _GNU_SOURCE\n#include \nint getnameinfo(const struct sockaddr *, socklen_t, char *, socklen_t, char *, socklen_t, int);int main() {\nreturn 0;}' ; then 188 | # GLIBC < 2.14 189 | if ! check_compile 'whether getnameinfo() flags argument is unsigned' "-DGN_NODELEN_T=socklen_t -DGN_SERVLEN_T=socklen_t -DGN_FLAGS_T=unsigned" \ 190 | '#define _GNU_SOURCE\n#include \nint getnameinfo(const struct sockaddr *, socklen_t, char *, socklen_t, char *, socklen_t, unsigned);int main() {\nreturn 0;}' ; then 191 | if ! check_compile 'whether getnameinfo() servlen argument is size_t' "-DGN_NODELEN_T=socklen_t -DGN_SERVLEN_T=size_t -DGN_FLAGS_T=int" \ 192 | '#define _GNU_SOURCE\n#include \nint getnameinfo(const struct sockaddr *, socklen_t, char *, socklen_t, char *, size_t, int);int main() {\nreturn 0;}' ; then 193 | # OpenBSD & FreeBSD 194 | if ! check_compile 'whether getnameinfo() servlen and nodelen argument is size_t' "-DGN_NODELEN_T=size_t -DGN_SERVLEN_T=size_t -DGN_FLAGS_T=int" \ 195 | '#define _GNU_SOURCE\n#include \nint getnameinfo(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int);int main() {\nreturn 0;}' ; then 196 | fail "failed to detect getnameinfo signature" 197 | fi 198 | fi 199 | fi 200 | fi 201 | 202 | check_compile 'whether we have GNU-style getservbyname_r()' "-DHAVE_GNU_GETSERVBYNAME_R" \ 203 | '#define _GNU_SOURCE\n#include \nint main() {\nstruct servent *se = 0;struct servent se_buf;char buf[1024];\ngetservbyname_r("foo", (void*) 0, &se_buf, buf, sizeof(buf), &se);\nreturn 0;}' 204 | 205 | check_compile 'whether we have pipe2() and O_CLOEXEC' "-DHAVE_PIPE2" \ 206 | '#define _GNU_SOURCE\n#include \n#include \nint main() {\nint pipefd[2];\npipe2(pipefd, O_CLOEXEC);\nreturn 0;}' 207 | 208 | check_compile 'whether we have SOCK_CLOEXEC' "-DHAVE_SOCK_CLOEXEC" \ 209 | '#define _GNU_SOURCE\n#include \nint main() {\nreturn socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0);}' 210 | 211 | check_compile 'whether we have clock_gettime' "-DHAVE_CLOCK_GETTIME" \ 212 | '#define _GNU_SOURCE\n#include \nint main() {\nstruct timespec now;clock_gettime(CLOCK_REALTIME, &now);\nreturn now.tv_sec ^ now.tv_nsec;}' 213 | 214 | check_define __APPLE__ && { 215 | mac_detected=true 216 | check_define __x86_64__ && mac_64=true 217 | if test "$hookmethod" = auto ; then 218 | osver=$(get_define_stripped __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 2>/dev/null) 219 | test "$osver" -gt $((120000 - 1)) && hookmethod=dyld 220 | fi 221 | } 222 | check_define __FreeBSD__ && bsd_detected=true 223 | check_define __OpenBSD__ && { 224 | bsd_detected=true 225 | echo "CFLAGS+=-DIS_OPENBSD">>config.mak 226 | check_compile_run 'whether OpenBSDs fclose() (illegally) calls close()' \ 227 | '#include \n#include\nint close(int x){exit(0);}int main(){fclose(stdin);return 1;}' && \ 228 | OUR_CPPFLAGS="$OUR_CPPFLAGS -DBROKEN_FCLOSE" 229 | } 230 | check_define __sun && check_define __SVR4 && solaris_detected=true 231 | check_define __HAIKU__ && haiku_detected=true 232 | 233 | echo "CC=$CC">>config.mak 234 | [ -z "$CPPFLAGS" ] || echo "CPPFLAGS=$CPPFLAGS">>config.mak 235 | [ -z "$CFLAGS" ] || echo "USER_CFLAGS=$CFLAGS">>config.mak 236 | [ -z "$LDFLAGS" ] || echo "USER_LDFLAGS=$LDFLAGS">>config.mak 237 | echo prefix=$prefix>>config.mak 238 | echo exec_prefix=$exec_prefix>>config.mak 239 | echo bindir=$bindir>>config.mak 240 | echo libdir=$libdir>>config.mak 241 | echo includedir=$includedir>>config.mak 242 | echo sysconfdir=$sysconfdir>>config.mak 243 | [ "$ignore_cve" = "no" ] && echo "CPPFLAGS+= -DSUPER_SECURE">>config.mak 244 | [ -z "$OUR_CPPFLAGS" ] || echo "CPPFLAGS+= $OUR_CPPFLAGS" >>config.mak 245 | 246 | check_link "whether we can use -Wl,--no-as-needed" "-Wl,--no-as-needed" \ 247 | "int main() { return 0; }" || echo NO_AS_NEEDED= >> config.mak 248 | 249 | LD_SONAME_FLAG= 250 | printf "checking what's the option to use in linker to set library name ... " 251 | for o in --soname -h -soname -install_name; do 252 | check_link_silent "-shared -Wl,$o,libconftest.so" "void test_func(int a) {}" && LD_SONAME_FLAG=$o && break 253 | done 254 | if [ -z "$LD_SONAME_FLAG" ]; then 255 | printf '\ncannot find an option to set library name\n' 256 | exit 1 257 | fi 258 | echo "$LD_SONAME_FLAG" 259 | echo "LD_SET_SONAME = -Wl,$LD_SONAME_FLAG," >> config.mak 260 | 261 | if check_link "checking whether we can use -ldl" "-ldl" \ 262 | "int main(){return 0;}" ; then 263 | echo "LIBDL = -ldl" >> config.mak 264 | fi 265 | 266 | if check_link "checking whether we can use -lpthread" "-lpthread" \ 267 | "int main(){return 0;}" ; then 268 | echo "PTHREAD = -lpthread" >> config.mak 269 | else 270 | check_link "checking whether we can use -pthread" "-pthread" \ 271 | "int main(){return 0;}" || fail "no pthread support detected" 272 | echo "PTHREAD = -pthread" >> config.mak 273 | fi 274 | 275 | make_cmd=make 276 | if ismac ; then 277 | echo LDSO_SUFFIX=dylib>>config.mak 278 | echo MAC_CFLAGS+=-DIS_MAC=1>>config.mak 279 | if test "$hookmethod" = dyld ; then 280 | echo "using Monterey style DYLD hooking" 281 | echo "CFLAGS+=-DMONTEREY_HOOKING">>config.mak 282 | fi 283 | if ismac64 && [ "$fat_binary" = 1 ] ; then 284 | echo "Configuring a fat binary for i386 and x86_64" 285 | echo "MAC_CFLAGS+=-arch i386 -arch x86_64">>config.mak 286 | echo "FAT_LDFLAGS=-arch i386 -arch x86_64">>config.mak 287 | echo "FAT_BIN_LDFLAGS=-arch i386 -arch x86_64">>config.mak 288 | fi 289 | if [ "$fat_binary_m1" = 1 ] ; then 290 | echo "Configuring a fat binary for arm64[e] and x86_64" 291 | echo "MAC_CFLAGS+=-arch arm64 -arch arm64e -arch x86_64">>config.mak 292 | echo "FAT_LDFLAGS=-arch arm64 -arch arm64e -arch x86_64">>config.mak 293 | echo "FAT_BIN_LDFLAGS=-arch arm64 -arch x86_64">>config.mak 294 | fi 295 | if [ "$fat_binary_m2" = 1 ] ; then 296 | echo "Configuring a fat binary for arm64[e] and x86_64" 297 | echo "MAC_CFLAGS+=-arch arm64 -arch arm64e -arch x86_64">>config.mak 298 | echo "FAT_LDFLAGS=-arch arm64 -arch arm64e -arch x86_64">>config.mak 299 | echo "FAT_BIN_LDFLAGS=-arch arm64 -arch arm64e -arch x86_64">>config.mak 300 | fi 301 | elif isbsd ; then 302 | echo LIBDL=>>config.mak 303 | echo "CFLAGS+=-DIS_BSD">>config.mak 304 | make_cmd=gmake 305 | elif issolaris; then 306 | echo "CFLAGS+=-DIS_SOLARIS -D__EXTENSIONS__" >> config.mak 307 | echo "SOCKET_LIBS=-lsocket -lnsl" >> config.mak 308 | elif ishaiku ; then 309 | echo LIBDL=>>config.mak 310 | echo "CFLAGS+=-DIS_HAIKU" >> config.mak 311 | fi 312 | 313 | echo "Done, now run $make_cmd && $make_cmd install" 314 | if [ "$fat_binary_m2" = 1 ] ; then 315 | echo "Don't forget to run csrutil disable and sudo nvram boot-args=-arm64e_preview_abi" 316 | fi 317 | -------------------------------------------------------------------------------- /src/allocator_thread.c: -------------------------------------------------------------------------------- 1 | #undef _GNU_SOURCE 2 | #define _GNU_SOURCE 3 | #undef _POSIX_C_SOURCE 4 | #define _DARWIN_C_SOURCE 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "allocator_thread.h" 19 | #include "debug.h" 20 | #include "ip_type.h" 21 | #include "mutex.h" 22 | #include "hash.h" 23 | #include "remotedns.h" 24 | 25 | /* stuff for our internal translation table */ 26 | 27 | typedef struct { 28 | uint32_t hash; 29 | char* string; 30 | } string_hash_tuple; 31 | 32 | typedef struct { 33 | uint32_t counter; 34 | uint32_t capa; 35 | string_hash_tuple** list; 36 | } internal_ip_lookup_table; 37 | 38 | static void *dumpstring(char* s, size_t len) { 39 | char* p = malloc(len); 40 | if(p) memcpy(p, s, len); 41 | return p; 42 | } 43 | 44 | static pthread_mutex_t *internal_ips_lock; 45 | static internal_ip_lookup_table *internal_ips; 46 | 47 | uint32_t index_from_internal_ip(ip_type4 internalip) { 48 | PFUNC(); 49 | ip_type4 tmp = internalip; 50 | uint32_t ret; 51 | ret = tmp.octet[3] + (tmp.octet[2] << 8) + (tmp.octet[1] << 16); 52 | ret -= 1; 53 | return ret; 54 | } 55 | 56 | char *string_from_internal_ip(ip_type4 internalip) { 57 | PFUNC(); 58 | char *res = NULL; 59 | uint32_t index = index_from_internal_ip(internalip); 60 | if(index < internal_ips->counter) 61 | res = internal_ips->list[index]->string; 62 | return res; 63 | } 64 | 65 | extern unsigned int remote_dns_subnet; 66 | ip_type4 make_internal_ip(uint32_t index) { 67 | ip_type4 ret; 68 | index++; // so we can start at .0.0.1 69 | if(index > 0xFFFFFF) 70 | return IPT4_INVALID; 71 | ret.octet[0] = remote_dns_subnet & 0xFF; 72 | ret.octet[1] = (index & 0xFF0000) >> 16; 73 | ret.octet[2] = (index & 0xFF00) >> 8; 74 | ret.octet[3] = index & 0xFF; 75 | return ret; 76 | } 77 | 78 | static ip_type4 ip_from_internal_list(char* name, size_t len) { 79 | uint32_t hash = dalias_hash((char *) name); 80 | size_t i; 81 | ip_type4 res; 82 | void* new_mem; 83 | // see if we already have this dns entry saved. 84 | if(internal_ips->counter) { 85 | for(i = 0; i < internal_ips->counter; i++) { 86 | if(internal_ips->list[i]->hash == hash && !strcmp(name, internal_ips->list[i]->string)) { 87 | res = make_internal_ip(i); 88 | PDEBUG("got cached ip for %s\n", name); 89 | goto have_ip; 90 | } 91 | } 92 | } 93 | // grow list if needed. 94 | if(internal_ips->capa < internal_ips->counter + 1) { 95 | PDEBUG("realloc\n"); 96 | new_mem = realloc(internal_ips->list, (internal_ips->capa + 16) * sizeof(void *)); 97 | if(new_mem) { 98 | internal_ips->capa += 16; 99 | internal_ips->list = new_mem; 100 | } else { 101 | oom: 102 | PDEBUG("out of mem\n"); 103 | goto err_plus_unlock; 104 | } 105 | } 106 | 107 | res = make_internal_ip(internal_ips->counter); 108 | if(res.as_int == IPT4_INVALID.as_int) 109 | goto err_plus_unlock; 110 | 111 | string_hash_tuple tmp = { 0 }; 112 | new_mem = dumpstring((char*) &tmp, sizeof(string_hash_tuple)); 113 | if(!new_mem) 114 | goto oom; 115 | 116 | PDEBUG("creating new entry %d for ip of %s\n", (int) internal_ips->counter, name); 117 | 118 | internal_ips->list[internal_ips->counter] = new_mem; 119 | internal_ips->list[internal_ips->counter]->hash = hash; 120 | 121 | new_mem = dumpstring((char*) name, len); 122 | 123 | if(!new_mem) { 124 | internal_ips->list[internal_ips->counter] = 0; 125 | goto oom; 126 | } 127 | internal_ips->list[internal_ips->counter]->string = new_mem; 128 | 129 | internal_ips->counter += 1; 130 | 131 | have_ip: 132 | 133 | return res; 134 | err_plus_unlock: 135 | 136 | PDEBUG("return err\n"); 137 | return IPT4_INVALID; 138 | } 139 | 140 | /* stuff for communication with the allocator thread */ 141 | 142 | enum at_direction { 143 | ATD_SERVER = 0, 144 | ATD_CLIENT, 145 | ATD_MAX, 146 | }; 147 | 148 | static pthread_t allocator_thread; 149 | int req_pipefd[2]; 150 | int resp_pipefd[2]; 151 | 152 | static int wait_data(int readfd) { 153 | PFUNC(); 154 | fd_set fds; 155 | FD_ZERO(&fds); 156 | FD_SET(readfd, &fds); 157 | int ret; 158 | while((ret = select(readfd+1, &fds, NULL, NULL, NULL)) <= 0) { 159 | if(ret < 0) { 160 | int e = errno; 161 | if(e == EINTR) continue; 162 | #ifdef __GLIBC__ 163 | char emsg[1024]; 164 | char* x = strerror_r(errno, emsg, sizeof emsg); 165 | dprintf(2, "select2: %s\n", x); 166 | #endif 167 | return 0; 168 | } 169 | } 170 | return 1; 171 | } 172 | 173 | static int trywrite(int fd, void* buf, size_t bytes) { 174 | ssize_t ret; 175 | unsigned char *out = buf; 176 | again: 177 | ret = write(fd, out, bytes); 178 | switch(ret) { 179 | case -1: 180 | if(errno == EINTR) goto again; 181 | case 0: 182 | return 0; 183 | default: 184 | if(ret == bytes || !bytes) return 1; 185 | out += ret; 186 | bytes -= ret; 187 | goto again; 188 | } 189 | } 190 | 191 | static int sendmessage(enum at_direction dir, struct at_msg *msg) { 192 | static int* destfd[ATD_MAX] = { [ATD_SERVER] = &req_pipefd[1], [ATD_CLIENT] = &resp_pipefd[1] }; 193 | assert(msg->h.datalen <= MSG_LEN_MAX); 194 | int ret = trywrite(*destfd[dir], msg, sizeof (msg->h)+msg->h.datalen); 195 | assert(msg->h.datalen <= MSG_LEN_MAX); 196 | return ret; 197 | } 198 | 199 | static int tryread(int fd, void* buf, size_t bytes) { 200 | ssize_t ret; 201 | unsigned char *out = buf; 202 | again: 203 | ret = read(fd, out, bytes); 204 | switch(ret) { 205 | case -1: 206 | if(errno == EINTR) goto again; 207 | case 0: 208 | return 0; 209 | default: 210 | if(ret == bytes || !bytes) return 1; 211 | out += ret; 212 | bytes -= ret; 213 | goto again; 214 | } 215 | } 216 | static int readmsg(int fd, struct at_msg *msg) { 217 | int ret = tryread(fd, msg, sizeof(msg->h)); 218 | if(ret != 1) return ret; 219 | return tryread(fd, &msg->m, msg->h.datalen); 220 | } 221 | 222 | static int getmessage(enum at_direction dir, struct at_msg *msg) { 223 | static int* readfd[ATD_MAX] = { [ATD_SERVER] = &req_pipefd[0], [ATD_CLIENT] = &resp_pipefd[0] }; 224 | ssize_t ret; 225 | if((ret = wait_data(*readfd[dir]))) { 226 | if(!readmsg(*readfd[dir], msg)) 227 | return 0; 228 | assert(msg->h.datalen <= MSG_LEN_MAX); 229 | } 230 | return ret; 231 | } 232 | 233 | static void* threadfunc(void* x) { 234 | (void) x; 235 | int ret; 236 | struct at_msg msg; 237 | while((ret = getmessage(ATD_SERVER, &msg))) { 238 | switch(msg.h.msgtype) { 239 | case ATM_GETIP: 240 | /* client wants an ip for a DNS name. iterate our list and check if we have an existing entry. 241 | * if not, create a new one. */ 242 | msg.m.ip = ip_from_internal_list(msg.m.host, msg.h.datalen); 243 | msg.h.datalen = sizeof(ip_type4); 244 | break; 245 | case ATM_GETNAME: { 246 | char *host = string_from_internal_ip(msg.m.ip); 247 | if(host) { 248 | size_t l = strlen(host); 249 | assert(l+1 < MSG_LEN_MAX); 250 | memcpy(msg.m.host, host, l + 1); 251 | msg.h.datalen = l + 1; 252 | } else { 253 | msg.h.datalen = 0; 254 | } 255 | break; 256 | } 257 | case ATM_EXIT: 258 | return 0; 259 | default: 260 | abort(); 261 | } 262 | ret = sendmessage(ATD_CLIENT, &msg); 263 | } 264 | return 0; 265 | } 266 | 267 | /* API to access the internal ip mapping */ 268 | 269 | ip_type4 at_get_ip_for_host(char* host, size_t len) { 270 | ip_type4 readbuf; 271 | MUTEX_LOCK(internal_ips_lock); 272 | if(len > MSG_LEN_MAX) goto inv; 273 | struct at_msg msg = {.h.msgtype = ATM_GETIP, .h.datalen = len + 1 }; 274 | memcpy(msg.m.host, host, len+1); 275 | if(sendmessage(ATD_SERVER, &msg) && 276 | getmessage(ATD_CLIENT, &msg)) readbuf = msg.m.ip; 277 | else { 278 | inv: 279 | readbuf = IPT4_INVALID; 280 | } 281 | assert(msg.h.msgtype == ATM_GETIP); 282 | MUTEX_UNLOCK(internal_ips_lock); 283 | return readbuf; 284 | } 285 | 286 | size_t at_get_host_for_ip(ip_type4 ip, char* readbuf) { 287 | struct at_msg msg = {.h.msgtype = ATM_GETNAME, .h.datalen = sizeof(ip_type4), .m.ip = ip }; 288 | size_t res = 0; 289 | MUTEX_LOCK(internal_ips_lock); 290 | if(sendmessage(ATD_SERVER, &msg) && getmessage(ATD_CLIENT, &msg)) { 291 | if((int16_t) msg.h.datalen <= 0) res = 0; 292 | else { 293 | memcpy(readbuf, msg.m.host, msg.h.datalen); 294 | res = msg.h.datalen - 1; 295 | } 296 | } 297 | assert(msg.h.msgtype == ATM_GETNAME); 298 | MUTEX_UNLOCK(internal_ips_lock); 299 | return res; 300 | } 301 | 302 | 303 | static void initpipe(int* fds) { 304 | int retval; 305 | 306 | #ifdef HAVE_PIPE2 307 | retval = pipe2(fds, O_CLOEXEC); 308 | #else 309 | retval = pipe(fds); 310 | if(retval == 0) { 311 | fcntl(fds[0], F_SETFD, FD_CLOEXEC); 312 | fcntl(fds[1], F_SETFD, FD_CLOEXEC); 313 | } 314 | #endif 315 | if(retval == -1) { 316 | perror("pipe"); 317 | exit(1); 318 | } 319 | } 320 | 321 | #ifndef MAX 322 | #define MAX(x, y) ((x) > (y) ? (x) : (y)) 323 | #endif 324 | 325 | #if !defined(PTHREAD_STACK_MIN) || defined(__APPLE__) 326 | /* MAC says its min is 8KB, but then crashes in our face. thx hunkOLard */ 327 | #define PTHREAD_STACK_MIN 64*1024 328 | #endif 329 | 330 | /* initialize with pointers to shared memory. these will 331 | * be used to place responses and arguments */ 332 | void at_init(void) { 333 | PFUNC(); 334 | void *shm = mmap(0, 4096, PROT_WRITE|PROT_READ, MAP_ANON|MAP_SHARED, -1, 0); 335 | assert(shm); 336 | internal_ips_lock = shm; 337 | internal_ips = (void*)((char*)shm + 2048); 338 | 339 | MUTEX_INIT(internal_ips_lock); 340 | memset(internal_ips, 0, sizeof *internal_ips); 341 | initpipe(req_pipefd); 342 | initpipe(resp_pipefd); 343 | pthread_attr_t allocator_thread_attr; 344 | pthread_attr_init(&allocator_thread_attr); 345 | pthread_attr_setstacksize(&allocator_thread_attr, MAX(16 * 1024, PTHREAD_STACK_MIN)); 346 | pthread_create(&allocator_thread, &allocator_thread_attr, threadfunc, 0); 347 | pthread_attr_destroy(&allocator_thread_attr); 348 | } 349 | 350 | void at_close(void) { 351 | PFUNC(); 352 | const int msg = ATM_EXIT; 353 | write(req_pipefd[1], &msg, sizeof(int)); 354 | pthread_join(allocator_thread, NULL); 355 | close(req_pipefd[0]); 356 | close(req_pipefd[1]); 357 | close(resp_pipefd[0]); 358 | close(resp_pipefd[1]); 359 | MUTEX_DESTROY(internal_ips_lock); 360 | } 361 | -------------------------------------------------------------------------------- /src/allocator_thread.h: -------------------------------------------------------------------------------- 1 | #ifndef ALLOCATOR_THREAD_H 2 | #define ALLOCATOR_THREAD_H 3 | 4 | #include 5 | #include "ip_type.h" 6 | 7 | extern int req_pipefd[2]; 8 | extern int resp_pipefd[2]; 9 | 10 | void at_init(void); 11 | void at_close(void); 12 | size_t at_get_host_for_ip(ip_type4 ip, char* readbuf); 13 | ip_type4 at_get_ip_for_host(char* host, size_t len); 14 | 15 | //RcB: DEP "allocator_thread.c" 16 | #endif 17 | 18 | -------------------------------------------------------------------------------- /src/common.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include 3 | #include 4 | #include 5 | 6 | const char *proxy_type_strmap[] = { 7 | "http", 8 | "socks4", 9 | "socks5", 10 | }; 11 | 12 | const char *chain_type_strmap[] = { 13 | "dynamic_chain", 14 | "strict_chain", 15 | "random_chain", 16 | "round_robin_chain", 17 | }; 18 | 19 | const char *proxy_state_strmap[] = { 20 | "play", 21 | "down", 22 | "blocked", 23 | "busy", 24 | }; 25 | 26 | /* isnumericipv4() taken from libulz */ 27 | int pc_isnumericipv4(const char* ipstring) { 28 | size_t x = 0, n = 0, d = 0; 29 | int wasdot = 0; 30 | while(1) { 31 | switch(ipstring[x]) { 32 | case 0: goto done; 33 | case '.': 34 | if(!n || wasdot) return 0; 35 | d++; 36 | wasdot = 1; 37 | break; 38 | case '0': case '1': case '2': case '3': case '4': 39 | case '5': case '6': case '7': case '8': case '9': 40 | n++; 41 | wasdot = 0; 42 | break; 43 | default: 44 | return 0; 45 | } 46 | x++; 47 | } 48 | done: 49 | if(d == 3 && n >= 4 && n <= 12) return 1; 50 | return 0; 51 | } 52 | 53 | // stolen from libulz (C) rofl0r 54 | void pc_stringfromipv4(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes) { 55 | unsigned char *p; 56 | char *o = outbuf_16_bytes; 57 | unsigned char n; 58 | for(p = ip_buf_4_bytes; p < ip_buf_4_bytes + 4; p++) { 59 | n = *p; 60 | if(*p >= 100) { 61 | if(*p >= 200) 62 | *(o++) = '2'; 63 | else 64 | *(o++) = '1'; 65 | n %= 100; 66 | } 67 | if(*p >= 10) { 68 | *(o++) = (n / 10) + '0'; 69 | n %= 10; 70 | } 71 | *(o++) = n + '0'; 72 | *(o++) = '.'; 73 | } 74 | o[-1] = 0; 75 | } 76 | 77 | static int check_path(char *path) { 78 | if(!path) 79 | return 0; 80 | return access(path, R_OK) != -1; 81 | } 82 | 83 | char *get_config_path(char* default_path, char* pbuf, size_t bufsize) { 84 | char buf[512]; 85 | // top priority: user defined path 86 | char *path = default_path; 87 | if(check_path(path)) 88 | goto have; 89 | 90 | // priority 1: env var PROXYCHAINS_CONF_FILE 91 | path = getenv(PROXYCHAINS_CONF_FILE_ENV_VAR); 92 | if(check_path(path)) 93 | goto have; 94 | 95 | // priority 2; proxychains conf in actual dir 96 | path = getcwd(buf, sizeof(buf)); 97 | snprintf(pbuf, bufsize, "%s/%s", path, PROXYCHAINS_CONF_FILE); 98 | path = pbuf; 99 | if(check_path(path)) 100 | goto have; 101 | 102 | // priority 3; $HOME/.proxychains/proxychains.conf 103 | path = getenv("HOME"); 104 | snprintf(pbuf, bufsize, "%s/.proxychains/%s", path, PROXYCHAINS_CONF_FILE); 105 | path = pbuf; 106 | if(check_path(path)) 107 | goto have; 108 | 109 | // priority 3b: ~/config/settings/proxychains.conf (for haiku) 110 | path = getenv("HOME"); 111 | snprintf(pbuf, bufsize, "%s/config/settings/%s", path, PROXYCHAINS_CONF_FILE); 112 | path = pbuf; 113 | if(check_path(path)) 114 | goto have; 115 | 116 | // priority 4: $SYSCONFDIR/proxychains.conf 117 | path = SYSCONFDIR "/" PROXYCHAINS_CONF_FILE; 118 | if(check_path(path)) 119 | goto have; 120 | 121 | // priority 5: /etc/proxychains.conf 122 | path = "/etc/" PROXYCHAINS_CONF_FILE; 123 | if(check_path(path)) 124 | goto have; 125 | 126 | perror("couldnt find configuration file"); 127 | exit(1); 128 | 129 | return NULL; 130 | have: 131 | return path; 132 | } 133 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | #define PROXYCHAINS_CONF_FILE_ENV_VAR "PROXYCHAINS_CONF_FILE" 5 | #define PROXYCHAINS_QUIET_MODE_ENV_VAR "PROXYCHAINS_QUIET_MODE" 6 | #define PROXYCHAINS_CONF_FILE "proxychains.conf" 7 | #define LOG_PREFIX "[proxychains] " 8 | #ifndef SYSCONFDIR 9 | #define SYSCONFDIR "/etc" 10 | #endif 11 | 12 | #include 13 | 14 | extern const char *proxy_type_strmap[]; 15 | extern const char *chain_type_strmap[]; 16 | extern const char *proxy_state_strmap[]; 17 | 18 | char *get_config_path(char* default_path, char* pbuf, size_t bufsize); 19 | void pc_stringfromipv4(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes); 20 | int pc_isnumericipv4(const char* ipstring); 21 | 22 | //RcB: DEP "common.c" 23 | #endif 24 | -------------------------------------------------------------------------------- /src/core.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | core.c - description 3 | ------------------- 4 | begin : Tue May 14 2002 5 | copyright : netcreature (C) 2002 6 | email : netcreature@users.sourceforge.net 7 | *************************************************************************** 8 | * GPL * 9 | *************************************************************************** 10 | * * 11 | * This program is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU General Public License as published by * 13 | * the Free Software Foundation; either version 2 of the License, or * 14 | * (at your option) any later version. * 15 | * * 16 | ***************************************************************************/ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "core.h" 39 | #include "common.h" 40 | #include "rdns.h" 41 | #include "mutex.h" 42 | 43 | extern int tcp_read_time_out; 44 | extern int tcp_connect_time_out; 45 | extern int proxychains_quiet_mode; 46 | extern unsigned int proxychains_proxy_offset; 47 | extern unsigned int remote_dns_subnet; 48 | 49 | static int poll_retry(struct pollfd *fds, nfds_t nfsd, int timeout) { 50 | int ret; 51 | int time_remain = timeout; 52 | int time_elapsed = 0; 53 | 54 | struct timeval start_time; 55 | struct timeval tv; 56 | 57 | gettimeofday(&start_time, NULL); 58 | 59 | do { 60 | //printf("Retry %d\n", time_remain); 61 | ret = poll(fds, nfsd, time_remain); 62 | gettimeofday(&tv, NULL); 63 | time_elapsed = ((tv.tv_sec - start_time.tv_sec) * 1000 + (tv.tv_usec - start_time.tv_usec) / 1000); 64 | //printf("Time elapsed %d\n", time_elapsed); 65 | time_remain = timeout - time_elapsed; 66 | } while(ret == -1 && errno == EINTR && time_remain > 0); 67 | 68 | //if (ret == -1) 69 | //printf("Return %d %d %s\n", ret, errno, strerror(errno)); 70 | return ret; 71 | } 72 | 73 | static void encode_base_64(char *src, char *dest, int max_len) { 74 | static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 75 | int n, l, i; 76 | l = strlen(src); 77 | max_len = (max_len - 1) / 4; 78 | for(i = 0; i < max_len; i++, src += 3, l -= 3) { 79 | switch (l) { 80 | case 0: 81 | break; 82 | case 1: 83 | n = src[0] << 16; 84 | *dest++ = base64[(n >> 18) & 077]; 85 | *dest++ = base64[(n >> 12) & 077]; 86 | *dest++ = '='; 87 | *dest++ = '='; 88 | break; 89 | case 2: 90 | n = src[0] << 16 | src[1] << 8; 91 | *dest++ = base64[(n >> 18) & 077]; 92 | *dest++ = base64[(n >> 12) & 077]; 93 | *dest++ = base64[(n >> 6) & 077]; 94 | *dest++ = '='; 95 | break; 96 | default: 97 | n = src[0] << 16 | src[1] << 8 | src[2]; 98 | *dest++ = base64[(n >> 18) & 077]; 99 | *dest++ = base64[(n >> 12) & 077]; 100 | *dest++ = base64[(n >> 6) & 077]; 101 | *dest++ = base64[n & 077]; 102 | } 103 | if(l < 3) 104 | break; 105 | } 106 | *dest++ = 0; 107 | } 108 | 109 | void proxychains_write_log(char *str, ...) { 110 | char buff[1024*4]; 111 | va_list arglist; 112 | if(!proxychains_quiet_mode) { 113 | va_start(arglist, str); 114 | vsnprintf(buff, sizeof(buff), str, arglist); 115 | va_end(arglist); 116 | fprintf(stderr, "%s", buff); 117 | fflush(stderr); 118 | } 119 | } 120 | 121 | static int write_n_bytes(int fd, char *buff, size_t size) { 122 | int i = 0; 123 | size_t wrote = 0; 124 | for(;;) { 125 | i = write(fd, &buff[wrote], size - wrote); 126 | if(i <= 0) 127 | return i; 128 | wrote += i; 129 | if(wrote == size) 130 | return wrote; 131 | } 132 | } 133 | 134 | static int read_n_bytes(int fd, char *buff, size_t size) { 135 | int ready; 136 | size_t i; 137 | struct pollfd pfd[1]; 138 | 139 | pfd[0].fd = fd; 140 | pfd[0].events = POLLIN; 141 | for(i = 0; i < size; i++) { 142 | pfd[0].revents = 0; 143 | ready = poll_retry(pfd, 1, tcp_read_time_out); 144 | if(ready != 1 || !(pfd[0].revents & POLLIN) || 1 != read(fd, &buff[i], 1)) 145 | return -1; 146 | } 147 | return (int) size; 148 | } 149 | 150 | static int timed_connect(int sock, const struct sockaddr *addr, socklen_t len) { 151 | int ret, value; 152 | socklen_t value_len; 153 | struct pollfd pfd[1]; 154 | PFUNC(); 155 | 156 | pfd[0].fd = sock; 157 | pfd[0].events = POLLOUT; 158 | fcntl(sock, F_SETFL, O_NONBLOCK); 159 | ret = true_connect(sock, addr, len); 160 | PDEBUG("\nconnect ret=%d\n", ret); 161 | 162 | if(ret == -1 && errno == EINPROGRESS) { 163 | ret = poll_retry(pfd, 1, tcp_connect_time_out); 164 | PDEBUG("\npoll ret=%d\n", ret); 165 | if(ret == 1) { 166 | value_len = sizeof(socklen_t); 167 | getsockopt(sock, SOL_SOCKET, SO_ERROR, &value, &value_len); 168 | PDEBUG("\nvalue=%d\n", value); 169 | if(!value) 170 | ret = 0; 171 | else 172 | ret = -1; 173 | } else { 174 | ret = -1; 175 | } 176 | } else { 177 | #ifdef DEBUG 178 | if(ret == -1) 179 | perror("true_connect"); 180 | #endif 181 | if(ret != 0) 182 | ret = -1; 183 | } 184 | 185 | fcntl(sock, F_SETFL, !O_NONBLOCK); 186 | return ret; 187 | } 188 | 189 | 190 | #define INVALID_INDEX 0xFFFFFFFFU 191 | #define BUFF_SIZE 1024 // used to read responses from proxies. 192 | static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, char *user, char *pass) { 193 | char *dns_name = NULL; 194 | char hostnamebuf[MSG_LEN_MAX]; 195 | size_t dns_len = 0; 196 | 197 | PFUNC(); 198 | 199 | // we use ip addresses with 224.* to lookup their dns name in our table, to allow remote DNS resolution 200 | // the range 224-255.* is reserved, and it won't go outside (unless the app does some other stuff with 201 | // the results returned from gethostbyname et al.) 202 | // the hardcoded number 224 can now be changed using the config option remote_dns_subnet to i.e. 127 203 | if(!ip.is_v6 && proxychains_resolver >= DNSLF_RDNS_START && ip.addr.v4.octet[0] == remote_dns_subnet) { 204 | dns_len = rdns_get_host_for_ip(ip.addr.v4, hostnamebuf); 205 | if(!dns_len) goto err; 206 | else dns_name = hostnamebuf; 207 | } 208 | 209 | PDEBUG("host dns %s\n", dns_name ? dns_name : ""); 210 | 211 | size_t ulen = strlen(user); 212 | size_t passlen = strlen(pass); 213 | 214 | if(ulen > 0xFF || passlen > 0xFF || dns_len > 0xFF) { 215 | proxychains_write_log(LOG_PREFIX "error: maximum size of 255 for user/pass or domain name!\n"); 216 | goto err; 217 | } 218 | 219 | int len; 220 | unsigned char buff[BUFF_SIZE]; 221 | char ip_buf[INET6_ADDRSTRLEN]; 222 | int v6 = ip.is_v6; 223 | 224 | switch (pt) { 225 | case RAW_TYPE: { 226 | return SUCCESS; 227 | } 228 | break; 229 | case HTTP_TYPE:{ 230 | if(!dns_len) { 231 | if(!inet_ntop(v6?AF_INET6:AF_INET,ip.addr.v6,ip_buf,sizeof ip_buf)) { 232 | proxychains_write_log(LOG_PREFIX "error: ip address conversion failed\n"); 233 | goto err; 234 | } 235 | dns_name = ip_buf; 236 | } 237 | #define HTTP_AUTH_MAX ((0xFF * 2) + 1 + 1) /* 2 * 0xff: username and pass, plus 1 for ':' and 1 for zero terminator. */ 238 | char src[HTTP_AUTH_MAX]; 239 | char dst[(4 * HTTP_AUTH_MAX)]; 240 | if(ulen) { 241 | snprintf(src, sizeof(src), "%s:%s", user, pass); 242 | encode_base_64(src, dst, sizeof(dst)); 243 | } else dst[0] = 0; 244 | 245 | uint16_t hs_port = ntohs(port); 246 | len = snprintf((char *) buff, sizeof(buff), 247 | "CONNECT %s:%d HTTP/1.0\r\nHost: %s:%d\r\n%s%s%s\r\n", 248 | dns_name, hs_port, 249 | dns_name, hs_port, 250 | ulen ? "Proxy-Authorization: Basic " : dst, 251 | dst, ulen ? "\r\n" : dst); 252 | 253 | if(len < 0 || len != send(sock, buff, len, 0)) 254 | goto err; 255 | 256 | len = 0; 257 | // read header byte by byte. 258 | while(len < BUFF_SIZE) { 259 | if(1 == read_n_bytes(sock, (char *) (buff + len), 1)) 260 | len++; 261 | else 262 | goto err; 263 | if(len > 4 && 264 | buff[len - 1] == '\n' && 265 | buff[len - 2] == '\r' && buff[len - 3] == '\n' && buff[len - 4] == '\r') 266 | break; 267 | } 268 | 269 | // if not ok (200) or response greather than BUFF_SIZE return BLOCKED; 270 | if(len == BUFF_SIZE || !(buff[9] == '2' && buff[10] == '0' && buff[11] == '0')) { 271 | PDEBUG("HTTP proxy blocked: buff=\"%s\"\n", buff); 272 | return BLOCKED; 273 | } 274 | 275 | return SUCCESS; 276 | } 277 | break; 278 | case SOCKS4_TYPE:{ 279 | if(v6) { 280 | proxychains_write_log(LOG_PREFIX "error: SOCKS4 doesn't support ipv6 addresses\n"); 281 | goto err; 282 | } 283 | buff[0] = 4; // socks version 284 | buff[1] = 1; // connect command 285 | memcpy(&buff[2], &port, 2); // dest port 286 | if(dns_len) { 287 | ip.addr.v4.octet[0] = 0; 288 | ip.addr.v4.octet[1] = 0; 289 | ip.addr.v4.octet[2] = 0; 290 | ip.addr.v4.octet[3] = 1; 291 | } 292 | memcpy(&buff[4], &ip.addr.v4, 4); // dest host 293 | len = ulen + 1; // username 294 | if(len > 1) 295 | memcpy(&buff[8], user, len); 296 | else { 297 | buff[8] = 0; 298 | } 299 | 300 | // do socksv4a dns resolution on the server 301 | if(dns_len) { 302 | memcpy(&buff[8 + len], dns_name, dns_len + 1); 303 | len += dns_len + 1; 304 | } 305 | 306 | if((len + 8) != write_n_bytes(sock, (char *) buff, (8 + len))) 307 | goto err; 308 | 309 | if(8 != read_n_bytes(sock, (char *) buff, 8)) 310 | goto err; 311 | 312 | if(buff[0] != 0 || buff[1] != 90) 313 | return BLOCKED; 314 | 315 | return SUCCESS; 316 | } 317 | break; 318 | case SOCKS5_TYPE:{ 319 | int n_methods = ulen ? 2 : 1; 320 | buff[0] = 5; // version 321 | buff[1] = n_methods ; // number of methods 322 | buff[2] = 0; // no auth method 323 | if(ulen) buff[3] = 2; /// auth method -> username / password 324 | if(2+n_methods != write_n_bytes(sock, (char *) buff, 2+n_methods)) 325 | goto err; 326 | 327 | if(2 != read_n_bytes(sock, (char *) buff, 2)) 328 | goto err; 329 | 330 | if(buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) { 331 | if(buff[0] == 5 && buff[1] == 0xFF) 332 | return BLOCKED; 333 | else 334 | goto err; 335 | } 336 | 337 | if(buff[1] == 2) { 338 | // authentication 339 | char in[2]; 340 | char out[515]; 341 | char *cur = out; 342 | size_t c; 343 | *cur++ = 1; // version 344 | c = ulen & 0xFF; 345 | *cur++ = c; 346 | memcpy(cur, user, c); 347 | cur += c; 348 | c = passlen & 0xFF; 349 | *cur++ = c; 350 | memcpy(cur, pass, c); 351 | cur += c; 352 | 353 | if((cur - out) != write_n_bytes(sock, out, cur - out)) 354 | goto err; 355 | 356 | 357 | if(2 != read_n_bytes(sock, in, 2)) 358 | goto err; 359 | /* according to RFC 1929 the version field for the user/pass auth sub- 360 | negotiation should be 1, which is kinda counter-intuitive, so there 361 | are some socks5 proxies that return 5 instead. other programs like 362 | curl work fine when the version is 5, so let's do the same and accept 363 | either of them. */ 364 | if(!(in[0] == 5 || in[0] == 1)) 365 | goto err; 366 | if(in[1] != 0) 367 | return BLOCKED; 368 | } 369 | int buff_iter = 0; 370 | buff[buff_iter++] = 5; // version 371 | buff[buff_iter++] = 1; // connect 372 | buff[buff_iter++] = 0; // reserved 373 | 374 | if(!dns_len) { 375 | buff[buff_iter++] = v6 ? 4 : 1; // ip v4/v6 376 | memcpy(buff + buff_iter, ip.addr.v6, v6?16:4); // dest host 377 | buff_iter += v6?16:4; 378 | } else { 379 | buff[buff_iter++] = 3; //dns 380 | buff[buff_iter++] = dns_len & 0xFF; 381 | memcpy(buff + buff_iter, dns_name, dns_len); 382 | buff_iter += dns_len; 383 | } 384 | 385 | memcpy(buff + buff_iter, &port, 2); // dest port 386 | buff_iter += 2; 387 | 388 | 389 | if(buff_iter != write_n_bytes(sock, (char *) buff, buff_iter)) 390 | goto err; 391 | 392 | if(4 != read_n_bytes(sock, (char *) buff, 4)) 393 | goto err; 394 | 395 | if(buff[0] != 5 || buff[1] != 0) 396 | goto err; 397 | 398 | switch (buff[3]) { 399 | case 1: 400 | len = 4; 401 | break; 402 | case 4: 403 | len = 16; 404 | break; 405 | case 3: 406 | len = 0; 407 | if(1 != read_n_bytes(sock, (char *) &len, 1)) 408 | goto err; 409 | break; 410 | default: 411 | goto err; 412 | } 413 | 414 | if(len + 2 != read_n_bytes(sock, (char *) buff, len + 2)) 415 | goto err; 416 | 417 | return SUCCESS; 418 | } 419 | break; 420 | } 421 | 422 | err: 423 | return SOCKET_ERROR; 424 | } 425 | 426 | #define TP " ... " 427 | #define DT "Dynamic chain" 428 | #define ST "Strict chain" 429 | #define RT "Random chain" 430 | #define RRT "Round Robin chain" 431 | 432 | static int start_chain(int *fd, proxy_data * pd, char *begin_mark) { 433 | int v6 = pd->ip.is_v6; 434 | 435 | *fd = socket(v6?PF_INET6:PF_INET, SOCK_STREAM, 0); 436 | if(*fd == -1) 437 | goto error; 438 | 439 | char ip_buf[INET6_ADDRSTRLEN]; 440 | if(!inet_ntop(v6?AF_INET6:AF_INET,pd->ip.addr.v6,ip_buf,sizeof ip_buf)) 441 | goto error; 442 | 443 | proxychains_write_log(LOG_PREFIX "%s " TP " %s:%d ", 444 | begin_mark, ip_buf, htons(pd->port)); 445 | pd->ps = PLAY_STATE; 446 | struct sockaddr_in addr = { 447 | .sin_family = AF_INET, 448 | .sin_port = pd->port, 449 | .sin_addr.s_addr = (in_addr_t) pd->ip.addr.v4.as_int 450 | }; 451 | struct sockaddr_in6 addr6 = { 452 | .sin6_family = AF_INET6, 453 | .sin6_port = pd->port, 454 | }; 455 | if(v6) memcpy(&addr6.sin6_addr.s6_addr, pd->ip.addr.v6, 16); 456 | if(timed_connect(*fd, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr))) { 457 | pd->ps = DOWN_STATE; 458 | goto error1; 459 | } 460 | pd->ps = BUSY_STATE; 461 | return SUCCESS; 462 | error1: 463 | proxychains_write_log(TP " timeout\n"); 464 | error: 465 | if(*fd != -1) { 466 | close(*fd); 467 | *fd = -1; 468 | } 469 | return SOCKET_ERROR; 470 | } 471 | 472 | static proxy_data *select_proxy(select_type how, proxy_data * pd, unsigned int proxy_count, unsigned int *offset) { 473 | unsigned int i = 0, k = 0; 474 | if(*offset >= proxy_count) 475 | return NULL; 476 | switch (how) { 477 | case RANDOMLY: 478 | do { 479 | k++; 480 | i = rand() % proxy_count; 481 | } while(pd[i].ps != PLAY_STATE && k < proxy_count * 100); 482 | break; 483 | case FIFOLY: 484 | for(i = *offset; i < proxy_count; i++) { 485 | if(pd[i].ps == PLAY_STATE) { 486 | *offset = i; 487 | break; 488 | } 489 | } 490 | default: 491 | break; 492 | } 493 | if(i >= proxy_count) 494 | i = 0; 495 | return (pd[i].ps == PLAY_STATE) ? &pd[i] : NULL; 496 | } 497 | 498 | 499 | static void release_all(proxy_data * pd, unsigned int proxy_count) { 500 | unsigned int i; 501 | for(i = 0; i < proxy_count; i++) 502 | pd[i].ps = PLAY_STATE; 503 | return; 504 | } 505 | 506 | static void release_busy(proxy_data * pd, unsigned int proxy_count) { 507 | unsigned int i; 508 | for(i = 0; i < proxy_count; i++) 509 | if(pd[i].ps == BUSY_STATE) 510 | pd[i].ps = PLAY_STATE; 511 | return; 512 | } 513 | 514 | static unsigned int calc_alive(proxy_data * pd, unsigned int proxy_count) { 515 | unsigned int i; 516 | int alive_count = 0; 517 | release_busy(pd, proxy_count); 518 | for(i = 0; i < proxy_count; i++) 519 | if(pd[i].ps == PLAY_STATE) 520 | alive_count++; 521 | return alive_count; 522 | } 523 | 524 | 525 | static int chain_step(int *ns, proxy_data * pfrom, proxy_data * pto) { 526 | int retcode = -1; 527 | char *hostname, *errmsg = 0; 528 | char hostname_buf[MSG_LEN_MAX]; 529 | char ip_buf[INET6_ADDRSTRLEN]; 530 | int v6 = pto->ip.is_v6; 531 | 532 | PFUNC(); 533 | 534 | if(!v6 && proxychains_resolver >= DNSLF_RDNS_START && pto->ip.addr.v4.octet[0] == remote_dns_subnet) { 535 | if(!rdns_get_host_for_ip(pto->ip.addr.v4, hostname_buf)) goto usenumericip; 536 | else hostname = hostname_buf; 537 | } else { 538 | usenumericip: 539 | if(!inet_ntop(v6?AF_INET6:AF_INET,pto->ip.addr.v6,ip_buf,sizeof ip_buf)) { 540 | pto->ps = DOWN_STATE; 541 | errmsg = "<--ip conversion error!\n"; 542 | retcode = SOCKET_ERROR; 543 | goto err; 544 | } 545 | hostname = ip_buf; 546 | } 547 | 548 | proxychains_write_log(TP " %s:%d ", hostname, htons(pto->port)); 549 | retcode = tunnel_to(*ns, pto->ip, pto->port, pfrom->pt, pfrom->user, pfrom->pass); 550 | switch (retcode) { 551 | case SUCCESS: 552 | pto->ps = BUSY_STATE; 553 | break; 554 | case BLOCKED: 555 | pto->ps = BLOCKED_STATE; 556 | errmsg = "<--denied\n"; 557 | goto err; 558 | case SOCKET_ERROR: 559 | pto->ps = DOWN_STATE; 560 | errmsg = "<--socket error or timeout!\n"; 561 | goto err; 562 | } 563 | return retcode; 564 | err: 565 | if(errmsg) proxychains_write_log(errmsg); 566 | if(*ns != -1) close(*ns); 567 | *ns = -1; 568 | return retcode; 569 | } 570 | 571 | int connect_proxy_chain(int sock, ip_type target_ip, 572 | unsigned short target_port, proxy_data * pd, 573 | unsigned int proxy_count, chain_type ct, unsigned int max_chain) { 574 | proxy_data p4; 575 | proxy_data *p1, *p2, *p3; 576 | int ns = -1; 577 | int rc = -1; 578 | unsigned int offset = 0; 579 | unsigned int alive_count = 0; 580 | unsigned int curr_len = 0; 581 | unsigned int looped = 0; // went back to start of list in RR mode 582 | unsigned int rr_loop_max = 14; 583 | 584 | p3 = &p4; 585 | 586 | PFUNC(); 587 | 588 | again: 589 | rc = -1; 590 | DUMP_PROXY_CHAIN(pd, proxy_count); 591 | 592 | switch (ct) { 593 | case DYNAMIC_TYPE: 594 | alive_count = calc_alive(pd, proxy_count); 595 | offset = 0; 596 | do { 597 | if(!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) 598 | goto error_more; 599 | } while(SUCCESS != start_chain(&ns, p1, DT) && offset < proxy_count); 600 | for(;;) { 601 | p2 = select_proxy(FIFOLY, pd, proxy_count, &offset); 602 | if(!p2) 603 | break; 604 | if(SUCCESS != chain_step(&ns, p1, p2)) { 605 | PDEBUG("GOTO AGAIN 1\n"); 606 | goto again; 607 | } 608 | p1 = p2; 609 | } 610 | //proxychains_write_log(TP); 611 | p3->ip = target_ip; 612 | p3->port = target_port; 613 | if(SUCCESS != chain_step(&ns, p1, p3)) 614 | goto error; 615 | break; 616 | 617 | case ROUND_ROBIN_TYPE: 618 | alive_count = calc_alive(pd, proxy_count); 619 | offset = proxychains_proxy_offset; 620 | if(alive_count < max_chain) 621 | goto error_more; 622 | PDEBUG("1:rr_offset = %d\n", offset); 623 | /* Check from current RR offset til end */ 624 | for (;rc != SUCCESS;) { 625 | if (!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) { 626 | /* We've reached the end of the list, go to the start */ 627 | offset = 0; 628 | looped++; 629 | if (looped > rr_loop_max) { 630 | proxychains_proxy_offset = 0; 631 | goto error_more; 632 | } else { 633 | PDEBUG("rr_type all proxies down, release all\n"); 634 | release_all(pd, proxy_count); 635 | /* Each loop we wait 10ms more */ 636 | usleep(10000 * looped); 637 | continue; 638 | } 639 | } 640 | PDEBUG("2:rr_offset = %d\n", offset); 641 | rc=start_chain(&ns, p1, RRT); 642 | } 643 | /* Create rest of chain using RR */ 644 | for(curr_len = 1; curr_len < max_chain;) { 645 | PDEBUG("3:rr_offset = %d, curr_len = %d, max_chain = %d\n", offset, curr_len, max_chain); 646 | p2 = select_proxy(FIFOLY, pd, proxy_count, &offset); 647 | if(!p2) { 648 | /* Try from the beginning to where we started */ 649 | offset = 0; 650 | continue; 651 | } else if(SUCCESS != chain_step(&ns, p1, p2)) { 652 | PDEBUG("GOTO AGAIN 1\n"); 653 | goto again; 654 | } else 655 | p1 = p2; 656 | curr_len++; 657 | } 658 | //proxychains_write_log(TP); 659 | p3->ip = target_ip; 660 | p3->port = target_port; 661 | proxychains_proxy_offset = offset+1; 662 | PDEBUG("pd_offset = %d, curr_len = %d\n", proxychains_proxy_offset, curr_len); 663 | if(SUCCESS != chain_step(&ns, p1, p3)) 664 | goto error; 665 | break; 666 | 667 | case STRICT_TYPE: 668 | alive_count = calc_alive(pd, proxy_count); 669 | offset = 0; 670 | if(!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) { 671 | PDEBUG("select_proxy failed\n"); 672 | goto error_strict; 673 | } 674 | if(SUCCESS != start_chain(&ns, p1, ST)) { 675 | PDEBUG("start_chain failed\n"); 676 | goto error_strict; 677 | } 678 | while(offset < proxy_count) { 679 | if(!(p2 = select_proxy(FIFOLY, pd, proxy_count, &offset))) 680 | break; 681 | if(SUCCESS != chain_step(&ns, p1, p2)) { 682 | PDEBUG("chain_step failed\n"); 683 | goto error_strict; 684 | } 685 | p1 = p2; 686 | } 687 | //proxychains_write_log(TP); 688 | p3->ip = target_ip; 689 | p3->port = target_port; 690 | if(SUCCESS != chain_step(&ns, p1, p3)) 691 | goto error; 692 | break; 693 | 694 | case RANDOM_TYPE: 695 | alive_count = calc_alive(pd, proxy_count); 696 | if(alive_count < max_chain) 697 | goto error_more; 698 | curr_len = offset = 0; 699 | do { 700 | if(!(p1 = select_proxy(RANDOMLY, pd, proxy_count, &offset))) 701 | goto error_more; 702 | } while(SUCCESS != start_chain(&ns, p1, RT) && offset < max_chain); 703 | while(++curr_len < max_chain) { 704 | if(!(p2 = select_proxy(RANDOMLY, pd, proxy_count, &offset))) 705 | goto error_more; 706 | if(SUCCESS != chain_step(&ns, p1, p2)) { 707 | PDEBUG("GOTO AGAIN 2\n"); 708 | goto again; 709 | } 710 | p1 = p2; 711 | } 712 | //proxychains_write_log(TP); 713 | p3->ip = target_ip; 714 | p3->port = target_port; 715 | if(SUCCESS != chain_step(&ns, p1, p3)) 716 | goto error; 717 | 718 | } 719 | 720 | proxychains_write_log(TP " OK\n"); 721 | dup2(ns, sock); 722 | close(ns); 723 | return 0; 724 | error: 725 | if(ns != -1) 726 | close(ns); 727 | errno = ECONNREFUSED; // for nmap ;) 728 | return -1; 729 | 730 | error_more: 731 | proxychains_write_log("\n!!!need more proxies!!!\n"); 732 | error_strict: 733 | PDEBUG("error\n"); 734 | 735 | release_all(pd, proxy_count); 736 | if(ns != -1) 737 | close(ns); 738 | errno = ETIMEDOUT; 739 | return -1; 740 | } 741 | 742 | static pthread_mutex_t servbyname_lock; 743 | void core_initialize(void) { 744 | MUTEX_INIT(&servbyname_lock); 745 | } 746 | 747 | void core_unload(void) { 748 | MUTEX_DESTROY(&servbyname_lock); 749 | } 750 | 751 | static void gethostbyname_data_setstring(struct gethostbyname_data* data, char* name) { 752 | snprintf(data->addr_name, sizeof(data->addr_name), "%s", name); 753 | data->hostent_space.h_name = data->addr_name; 754 | } 755 | 756 | extern ip_type4 hostsreader_get_numeric_ip_for_name(const char* name); 757 | struct hostent* proxy_gethostbyname_old(const char *name) 758 | { 759 | static struct hostent hostent_space; 760 | static in_addr_t resolved_addr; 761 | static char* resolved_addr_p; 762 | static char addr_name[256]; 763 | 764 | int pipe_fd[2]; 765 | char buff[256]; 766 | in_addr_t addr; 767 | pid_t pid; 768 | int status, ret; 769 | size_t l; 770 | struct hostent* hp; 771 | 772 | hostent_space.h_addr_list = &resolved_addr_p; 773 | *hostent_space.h_addr_list = (char*)&resolved_addr; 774 | resolved_addr = 0; 775 | 776 | if(pc_isnumericipv4(name)) { 777 | strcpy(buff, name); 778 | goto got_buff; 779 | } 780 | 781 | gethostname(buff,sizeof(buff)); 782 | if(!strcmp(buff,name)) 783 | goto got_buff; 784 | 785 | memset(buff, 0, sizeof(buff)); 786 | 787 | // TODO: this works only once, so cache it ... 788 | // later 789 | while ((hp=gethostent())) 790 | if (!strcmp(hp->h_name,name)) 791 | return hp; 792 | #ifdef HAVE_PIPE2 793 | ret = pipe2(pipe_fd, O_CLOEXEC); 794 | #else 795 | ret = pipe(pipe_fd); 796 | if(ret == 0) { 797 | fcntl(pipe_fd[0], F_SETFD, FD_CLOEXEC); 798 | fcntl(pipe_fd[1], F_SETFD, FD_CLOEXEC); 799 | } 800 | #endif 801 | 802 | if(ret) 803 | goto err; 804 | pid = fork(); 805 | switch(pid) { 806 | 807 | case 0: // child 808 | proxychains_write_log("|DNS-request| %s \n", name); 809 | close(pipe_fd[0]); 810 | dup2(pipe_fd[1],1); 811 | close(pipe_fd[1]); 812 | 813 | // putenv("LD_PRELOAD="); 814 | execlp("proxyresolv","proxyresolv",name,NULL); 815 | perror("can't exec proxyresolv"); 816 | exit(2); 817 | 818 | case -1: //error 819 | close(pipe_fd[0]); 820 | close(pipe_fd[1]); 821 | perror("can't fork"); 822 | goto err; 823 | 824 | default: 825 | close(pipe_fd[1]); 826 | waitpid(pid, &status, 0); 827 | buff[0] = 0; 828 | read(pipe_fd[0],&buff,sizeof(buff)); 829 | close(pipe_fd[0]); 830 | got_buff: 831 | l = strlen(buff); 832 | if (!l) goto err_dns; 833 | if (buff[l-1] == '\n') buff[l-1] = 0; 834 | addr = inet_addr(buff); 835 | if (addr == (in_addr_t) (-1)) 836 | goto err_dns; 837 | memcpy(*(hostent_space.h_addr_list), 838 | &addr ,sizeof(struct in_addr)); 839 | hostent_space.h_name = addr_name; 840 | snprintf(addr_name, sizeof addr_name, "%s", buff); 841 | hostent_space.h_length = sizeof (in_addr_t); 842 | hostent_space.h_addrtype = AF_INET; 843 | } 844 | proxychains_write_log("|DNS-response| %s is %s\n", 845 | name, inet_ntoa(*(struct in_addr*)&addr)); 846 | return &hostent_space; 847 | err_dns: 848 | proxychains_write_log("|DNS-response|: %s lookup error\n", name); 849 | err: 850 | return NULL; 851 | } 852 | 853 | struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* data) { 854 | PFUNC(); 855 | char buff[256]; 856 | 857 | data->resolved_addr_p[0] = (char *) &data->resolved_addr; 858 | data->resolved_addr_p[1] = NULL; 859 | 860 | data->hostent_space.h_addr_list = data->resolved_addr_p; 861 | // let aliases point to the NULL member, mimicking an empty list. 862 | data->hostent_space.h_aliases = &data->resolved_addr_p[1]; 863 | 864 | data->resolved_addr = 0; 865 | data->hostent_space.h_addrtype = AF_INET; 866 | data->hostent_space.h_length = sizeof(in_addr_t); 867 | 868 | if(pc_isnumericipv4(name)) { 869 | data->resolved_addr = inet_addr(name); 870 | goto retname; 871 | } 872 | 873 | gethostname(buff, sizeof(buff)); 874 | 875 | if(!strcmp(buff, name)) { 876 | data->resolved_addr = inet_addr(buff); 877 | if(data->resolved_addr == (in_addr_t) (-1)) 878 | data->resolved_addr = (in_addr_t) (IPT4_LOCALHOST.as_int); 879 | goto retname; 880 | } 881 | 882 | // this iterates over the "known hosts" db, usually /etc/hosts 883 | ip_type4 hdb_res = hostsreader_get_numeric_ip_for_name(name); 884 | if(hdb_res.as_int != IPT4_INVALID.as_int) { 885 | data->resolved_addr = hdb_res.as_int; 886 | goto retname; 887 | } 888 | 889 | data->resolved_addr = rdns_get_ip_for_host((char*) name, strlen(name)).as_int; 890 | if(data->resolved_addr == (in_addr_t) IPT4_INVALID.as_int) return NULL; 891 | 892 | retname: 893 | 894 | gethostbyname_data_setstring(data, (char*) name); 895 | 896 | PDEBUG("return hostent space\n"); 897 | 898 | return &data->hostent_space; 899 | } 900 | 901 | struct addrinfo_data { 902 | struct addrinfo addrinfo_space; 903 | struct sockaddr_storage sockaddr_space; 904 | char addr_name[256]; 905 | }; 906 | 907 | void proxy_freeaddrinfo(struct addrinfo *res) { 908 | PFUNC(); 909 | free(res); 910 | } 911 | 912 | static int mygetservbyname_r(const char* name, const char* proto, struct servent* result_buf, 913 | char* buf, size_t buflen, struct servent** result) { 914 | PFUNC(); 915 | #ifdef HAVE_GNU_GETSERVBYNAME_R 916 | PDEBUG("using host getservbyname_r\n"); 917 | return getservbyname_r(name, proto, result_buf, buf, buflen, result); 918 | #endif 919 | struct servent *res; 920 | int ret; 921 | (void) buf; (void) buflen; 922 | MUTEX_LOCK(&servbyname_lock); 923 | res = getservbyname(name, proto); 924 | if(res) { 925 | *result_buf = *res; 926 | *result = result_buf; 927 | ret = 0; 928 | } else { 929 | *result = NULL; 930 | ret = ENOENT; 931 | } 932 | MUTEX_UNLOCK(&servbyname_lock); 933 | return ret; 934 | } 935 | 936 | static int looks_like_numeric_ipv6(const char *node) 937 | { 938 | if(!strchr(node, ':')) return 0; 939 | const char* p= node; 940 | while(1) switch(*(p++)) { 941 | case 0: return 1; 942 | case ':': case '.': 943 | case '0': case '1': case '2': case '3': case '4': 944 | case '5': case '6': case '7': case '8': case '9': 945 | case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 946 | case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 947 | break; 948 | default: return 0; 949 | } 950 | } 951 | 952 | static int my_inet_aton(const char *node, struct addrinfo_data* space) 953 | { 954 | int ret; 955 | ((struct sockaddr_in *) &space->sockaddr_space)->sin_family = AF_INET; 956 | ret = inet_aton(node, &((struct sockaddr_in *) &space->sockaddr_space)->sin_addr); 957 | if(ret || !looks_like_numeric_ipv6(node)) return ret; 958 | ret = inet_pton(AF_INET6, node, &((struct sockaddr_in6 *) &space->sockaddr_space)->sin6_addr); 959 | if(ret) ((struct sockaddr_in6 *) &space->sockaddr_space)->sin6_family = AF_INET6; 960 | return ret; 961 | } 962 | 963 | int proxy_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { 964 | struct gethostbyname_data ghdata; 965 | struct addrinfo_data *space; 966 | struct servent *se = NULL; 967 | struct hostent *hp = NULL; 968 | struct servent se_buf; 969 | struct addrinfo *p; 970 | char buf[1024]; 971 | int port, af = AF_INET; 972 | 973 | PDEBUG("proxy_getaddrinfo node:%s service: %s, flags: %d\n", 974 | node?node:"",service?service:"",hints?(int)hints->ai_flags:0); 975 | 976 | space = calloc(1, sizeof(struct addrinfo_data)); 977 | if(!space) return EAI_MEMORY; 978 | 979 | if(node && !my_inet_aton(node, space)) { 980 | /* some folks (nmap) use getaddrinfo() with AI_NUMERICHOST to check whether a string 981 | containing a numeric ip was passed. we must return failure in that case. */ 982 | if(hints && (hints->ai_flags & AI_NUMERICHOST)) { 983 | err_nn: 984 | free(space); 985 | return EAI_NONAME; 986 | } 987 | if(proxychains_resolver == DNSLF_FORKEXEC) 988 | hp = proxy_gethostbyname_old(node); 989 | else 990 | hp = proxy_gethostbyname(node, &ghdata); 991 | 992 | if(hp) 993 | memcpy(&((struct sockaddr_in *) &space->sockaddr_space)->sin_addr, 994 | *(hp->h_addr_list), sizeof(in_addr_t)); 995 | else 996 | goto err_nn; 997 | } else if(node) { 998 | af = ((struct sockaddr_in *) &space->sockaddr_space)->sin_family; 999 | } else if(!node && !(hints->ai_flags & AI_PASSIVE)) { 1000 | af = ((struct sockaddr_in *) &space->sockaddr_space)->sin_family = AF_INET; 1001 | memcpy(&((struct sockaddr_in *) &space->sockaddr_space)->sin_addr, 1002 | "\177\0\0\1", 4); 1003 | } 1004 | if(service) mygetservbyname_r(service, NULL, &se_buf, buf, sizeof(buf), &se); 1005 | 1006 | port = se ? se->s_port : htons(atoi(service ? service : "0")); 1007 | if(af == AF_INET) 1008 | ((struct sockaddr_in *) &space->sockaddr_space)->sin_port = port; 1009 | else 1010 | ((struct sockaddr_in6 *) &space->sockaddr_space)->sin6_port = port; 1011 | 1012 | *res = p = &space->addrinfo_space; 1013 | assert((size_t)p == (size_t) space); 1014 | 1015 | p->ai_addr = (void*) &space->sockaddr_space; 1016 | if(node) 1017 | snprintf(space->addr_name, sizeof(space->addr_name), "%s", node); 1018 | p->ai_canonname = space->addr_name; 1019 | p->ai_next = NULL; 1020 | p->ai_family = space->sockaddr_space.ss_family = af; 1021 | p->ai_addrlen = af == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); 1022 | 1023 | if(hints) { 1024 | p->ai_socktype = hints->ai_socktype; 1025 | p->ai_flags = hints->ai_flags; 1026 | p->ai_protocol = hints->ai_protocol; 1027 | if(!p->ai_socktype && p->ai_protocol == IPPROTO_TCP) 1028 | p->ai_socktype = SOCK_STREAM; 1029 | } else { 1030 | #ifndef AI_V4MAPPED 1031 | #define AI_V4MAPPED 0 1032 | #endif 1033 | p->ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG); 1034 | } 1035 | return 0; 1036 | } 1037 | -------------------------------------------------------------------------------- /src/core.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | core.h - description 3 | ------------------- 4 | begin : Tue May 14 2002 5 | copyright : netcreature (C) 2002 6 | email : netcreature@users.sourceforge.net 7 | *************************************************************************** 8 | *************************************************************************** 9 | * * 10 | * This program is free software; you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation; either version 2 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | ***************************************************************************/ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #ifndef __CORE_HEADER 25 | #define __CORE_HEADER 26 | #define MAX_LOCALNET 64 27 | #define MAX_DNAT 64 28 | 29 | #include "ip_type.h" 30 | 31 | /*error codes*/ 32 | typedef enum { 33 | SUCCESS=0, 34 | MEMORY_FAIL, // malloc failed 35 | SOCKET_ERROR, // look errno for more 36 | CHAIN_DOWN, // no proxy in chain responds to tcp 37 | CHAIN_EMPTY, // if proxy_count = 0 38 | BLOCKED // target's port blocked on last proxy in the chain 39 | } ERR_CODE; 40 | 41 | typedef enum { 42 | HTTP_TYPE, 43 | SOCKS4_TYPE, 44 | SOCKS5_TYPE, 45 | RAW_TYPE 46 | } proxy_type; 47 | 48 | typedef enum { 49 | DYNAMIC_TYPE, 50 | STRICT_TYPE, 51 | RANDOM_TYPE, 52 | ROUND_ROBIN_TYPE 53 | } chain_type; 54 | 55 | typedef enum { 56 | PLAY_STATE, 57 | DOWN_STATE, 58 | BLOCKED_STATE, 59 | BUSY_STATE 60 | } proxy_state; 61 | 62 | typedef enum { 63 | RANDOMLY, 64 | FIFOLY 65 | } select_type; 66 | 67 | typedef struct { 68 | sa_family_t family; 69 | unsigned short port; 70 | union { 71 | struct { 72 | struct in_addr in_addr; 73 | struct in_addr in_mask; 74 | }; 75 | struct { 76 | struct in6_addr in6_addr; 77 | unsigned char in6_prefix; 78 | }; 79 | }; 80 | } localaddr_arg; 81 | 82 | typedef struct { 83 | struct in_addr orig_dst, new_dst; 84 | unsigned short orig_port, new_port; 85 | } dnat_arg; 86 | 87 | typedef struct { 88 | ip_type ip; 89 | unsigned short port; 90 | proxy_type pt; 91 | proxy_state ps; 92 | char user[256]; 93 | char pass[256]; 94 | } proxy_data; 95 | 96 | int connect_proxy_chain (int sock, ip_type target_ip, unsigned short target_port, 97 | proxy_data * pd, unsigned int proxy_count, chain_type ct, 98 | unsigned int max_chain ); 99 | 100 | void proxychains_write_log(char *str, ...); 101 | 102 | typedef int (*close_t)(int); 103 | typedef int (*close_range_t)(unsigned, unsigned, int); 104 | typedef int (*connect_t)(int, const struct sockaddr *, socklen_t); 105 | typedef struct hostent* (*gethostbyname_t)(const char *); 106 | typedef void (*freeaddrinfo_t)(struct addrinfo *); 107 | typedef struct hostent *(*gethostbyaddr_t) (const void *, socklen_t, int); 108 | 109 | typedef int (*getaddrinfo_t)(const char *, const char *, const struct addrinfo *, 110 | struct addrinfo **); 111 | 112 | typedef int (*getnameinfo_t) (const struct sockaddr *, socklen_t, char *, 113 | GN_NODELEN_T, char *, GN_SERVLEN_T, GN_FLAGS_T); 114 | 115 | typedef ssize_t (*sendto_t) (int sockfd, const void *buf, size_t len, int flags, 116 | const struct sockaddr *dest_addr, socklen_t addrlen); 117 | 118 | 119 | 120 | extern connect_t true_connect; 121 | extern gethostbyname_t true_gethostbyname; 122 | extern getaddrinfo_t true_getaddrinfo; 123 | extern freeaddrinfo_t true_freeaddrinfo; 124 | extern getnameinfo_t true_getnameinfo; 125 | extern gethostbyaddr_t true_gethostbyaddr; 126 | 127 | struct gethostbyname_data { 128 | struct hostent hostent_space; 129 | in_addr_t resolved_addr; 130 | char *resolved_addr_p[2]; 131 | char addr_name[256]; 132 | }; 133 | 134 | struct hostent* proxy_gethostbyname(const char *name, struct gethostbyname_data *data); 135 | struct hostent* proxy_gethostbyname_old(const char *name); 136 | 137 | int proxy_getaddrinfo(const char *node, const char *service, 138 | const struct addrinfo *hints, struct addrinfo **res); 139 | void proxy_freeaddrinfo(struct addrinfo *res); 140 | 141 | void core_initialize(void); 142 | void core_unload(void); 143 | 144 | #include "debug.h" 145 | 146 | #endif 147 | 148 | //RcB: DEP "core.c" 149 | //RcB: DEP "libproxychains.c" 150 | //RcB: LINK "-Wl,--no-as-needed -ldl -lpthread" 151 | 152 | -------------------------------------------------------------------------------- /src/daemon/daemon.c: -------------------------------------------------------------------------------- 1 | /* 2 | proxychains-ng DNS daemon 3 | 4 | Copyright (C) 2020 rofl0r. 5 | 6 | */ 7 | 8 | #define _GNU_SOURCE 9 | #include 10 | #define _POSIX_C_SOURCE 200809L 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "udpserver.h" 21 | #include "sblist.h" 22 | #include "hsearch.h" 23 | #include "../remotedns.h" 24 | #include "../ip_type.h" 25 | 26 | #ifndef MAX 27 | #define MAX(x, y) ((x) > (y) ? (x) : (y)) 28 | #endif 29 | 30 | static struct htab *ip_lookup_table; 31 | static sblist *hostnames; 32 | static unsigned remote_subnet; 33 | static const struct server* server; 34 | 35 | #ifndef CONFIG_LOG 36 | #define CONFIG_LOG 1 37 | #endif 38 | #if CONFIG_LOG 39 | /* we log to stderr because it's not using line buffering, i.e. malloc which would need 40 | locking when called from different threads. for the same reason we use dprintf, 41 | which writes directly to an fd. */ 42 | #define dolog(...) dprintf(2, __VA_ARGS__) 43 | #else 44 | static void dolog(const char* fmt, ...) { } 45 | #endif 46 | 47 | static char* my_inet_ntoa(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes) { 48 | unsigned char *p; 49 | char *o = outbuf_16_bytes; 50 | unsigned char n; 51 | for(p = ip_buf_4_bytes; p < ip_buf_4_bytes + 4; p++) { 52 | n = *p; 53 | if(*p >= 100) { 54 | if(*p >= 200) 55 | *(o++) = '2'; 56 | else 57 | *(o++) = '1'; 58 | n %= 100; 59 | } 60 | if(*p >= 10) { 61 | *(o++) = (n / 10) + '0'; 62 | n %= 10; 63 | } 64 | *(o++) = n + '0'; 65 | *(o++) = '.'; 66 | } 67 | o[-1] = 0; 68 | return outbuf_16_bytes; 69 | } 70 | 71 | 72 | /* buf needs to be long enough for an ipv6 addr, i.e. INET6_ADDRSTRLEN + 1 */ 73 | static char* ipstr(union sockaddr_union *su, char* buf) { 74 | int af = SOCKADDR_UNION_AF(su); 75 | void *ipdata = SOCKADDR_UNION_ADDRESS(su); 76 | inet_ntop(af, ipdata, buf, INET6_ADDRSTRLEN+1); 77 | char portbuf[7]; 78 | snprintf(portbuf, sizeof portbuf, ":%u", (unsigned) ntohs(SOCKADDR_UNION_PORT(su))); 79 | strcat(buf, portbuf); 80 | return buf; 81 | } 82 | 83 | static int usage(char *a0) { 84 | dprintf(2, 85 | "Proxychains-NG remote dns daemon\n" 86 | "--------------------------------\n" 87 | "usage: %s -i listenip -p port -r remotesubnet\n" 88 | "all arguments are optional.\n" 89 | "by default listenip is 127.0.0.1, port 1053 and remotesubnet 224.\n\n", a0 90 | ); 91 | return 1; 92 | } 93 | 94 | unsigned index_from_ip(ip_type4 internalip) { 95 | ip_type4 tmp = internalip; 96 | uint32_t ret; 97 | ret = tmp.octet[3] + (tmp.octet[2] << 8) + (tmp.octet[1] << 16); 98 | ret -= 1; 99 | return ret; 100 | } 101 | 102 | char *host_from_ip(ip_type4 internalip) { 103 | char *res = NULL; 104 | unsigned index = index_from_ip(internalip); 105 | if(index < sblist_getsize(hostnames)) { 106 | char **tmp = sblist_get(hostnames, index); 107 | if(tmp && *tmp) res = *tmp; 108 | } 109 | return res; 110 | } 111 | 112 | ip_type4 get_ip_from_index(unsigned index) { 113 | ip_type4 ret; 114 | index++; // so we can start at .0.0.1 115 | if(index > 0xFFFFFF) 116 | return IPT4_INVALID; 117 | ret.octet[0] = remote_subnet & 0xFF; 118 | ret.octet[1] = (index & 0xFF0000) >> 16; 119 | ret.octet[2] = (index & 0xFF00) >> 8; 120 | ret.octet[3] = index & 0xFF; 121 | return ret; 122 | } 123 | 124 | ip_type4 get_ip(char* hn) { 125 | htab_value *v = htab_find(ip_lookup_table, hn); 126 | if(v) return get_ip_from_index(v->n); 127 | char *n = strdup(hn); 128 | if(!n) return IPT4_INVALID; 129 | if(!sblist_add(hostnames, &n)) { 130 | o_out:; 131 | free(n); 132 | return IPT4_INVALID; 133 | } 134 | if(!htab_insert(ip_lookup_table, n, HTV_N(sblist_getsize(hostnames)-1))) { 135 | sblist_delete(hostnames, sblist_getsize(hostnames)-1); 136 | goto o_out; 137 | } 138 | return get_ip_from_index(sblist_getsize(hostnames)-1); 139 | } 140 | 141 | int main(int argc, char** argv) { 142 | int ch; 143 | const char *listenip = "127.0.0.1"; 144 | unsigned port = 1053; 145 | remote_subnet = 224; 146 | while((ch = getopt(argc, argv, ":r:i:p:")) != -1) { 147 | switch(ch) { 148 | case 'r': 149 | remote_subnet = atoi(optarg); 150 | break; 151 | case 'i': 152 | listenip = optarg; 153 | break; 154 | case 'p': 155 | port = atoi(optarg); 156 | break; 157 | case ':': 158 | dprintf(2, "error: option -%c requires an operand\n", optopt); 159 | /* fall through */ 160 | case '?': 161 | return usage(argv[0]); 162 | } 163 | } 164 | signal(SIGPIPE, SIG_IGN); 165 | struct server s; 166 | if(server_setup(&s, listenip, port)) { 167 | perror("server_setup"); 168 | return 1; 169 | } 170 | server = &s; 171 | 172 | ip_lookup_table = htab_create(64); 173 | hostnames = sblist_new(sizeof(char*), 64); 174 | 175 | while(1) { 176 | struct client c; 177 | char ipstr_buf[INET6_ADDRSTRLEN+6+1]; 178 | char ip4str_buf[16]; 179 | struct at_msg msg, out; 180 | size_t msgl = sizeof(msg); 181 | int failed = 0; 182 | 183 | #define FAIL() do { failed=1; goto sendresp; } while(0) 184 | 185 | if(server_waitclient(&s, &c, &msg, &msgl)) continue; 186 | msg.h.datalen = ntohs(msg.h.datalen); 187 | if(msgl != sizeof(msg.h)+msg.h.datalen) { 188 | dolog("%s: invalid datalen\n", ipstr(&c.addr, ipstr_buf)); 189 | FAIL(); 190 | } 191 | 192 | out.h.msgtype = msg.h.msgtype; 193 | if(msg.h.msgtype == ATM_GETIP) { 194 | if(!memchr(msg.m.host, 0, msg.h.datalen)) { 195 | dolog("%s: nul terminator missing\n", ipstr(&c.addr, ipstr_buf)); 196 | FAIL(); 197 | } 198 | out.h.datalen = sizeof(ip_type4); 199 | out.m.ip = get_ip(msg.m.host); 200 | failed = !memcmp(&out.m.ip, &IPT4_INVALID, 4); 201 | dolog("%s requested ip for %s (%s)\n", ipstr(&c.addr, ipstr_buf), 202 | msg.m.host, failed?"FAIL":my_inet_ntoa((void*)&out.m.ip, ip4str_buf)); 203 | if(failed) FAIL(); 204 | } else if (msg.h.msgtype == ATM_GETNAME) { 205 | if(msg.h.datalen != 4) { 206 | dolog("%s: invalid len for getname request\n", ipstr(&c.addr, ipstr_buf)); 207 | FAIL(); 208 | } 209 | char *hn = host_from_ip(msg.m.ip); 210 | if(hn) { 211 | size_t l = strlen(hn); 212 | memcpy(out.m.host, hn, l+1); 213 | out.h.datalen = l+1; 214 | } 215 | dolog("%s requested name for %s (%s)\n", ipstr(&c.addr, ipstr_buf), 216 | my_inet_ntoa((void*) &msg.m.ip, ip4str_buf), hn?hn:"FAIL"); 217 | if(!hn) FAIL(); 218 | } else { 219 | dolog("%s: unknown request %u\n", ipstr(&c.addr, ipstr_buf), 220 | (unsigned) msg.h.msgtype); 221 | } 222 | sendresp:; 223 | if(failed) { 224 | out.h.msgtype = ATM_FAIL; 225 | out.h.datalen = 0; 226 | } 227 | unsigned short dlen = out.h.datalen; 228 | out.h.datalen = htons(dlen); 229 | sendto(server->fd, &out, sizeof(out.h)+dlen, 0, (void*) &c.addr, SOCKADDR_UNION_LENGTH(&c.addr)); 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/daemon/hsearch.c: -------------------------------------------------------------------------------- 1 | /* 2 | musl license, hsearch.c originally written by Szabolcs Nagy 3 | 4 | Copyright © 2005-2020 Rich Felker, et al. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #include 27 | #include 28 | #include "hsearch.h" 29 | 30 | /* 31 | open addressing hash table with 2^n table size 32 | quadratic probing is used in case of hash collision 33 | tab indices and hash are size_t 34 | after resize fails with ENOMEM the state of tab is still usable 35 | */ 36 | 37 | typedef struct htab_entry { 38 | char *key; 39 | htab_value data; 40 | } htab_entry; 41 | 42 | struct elem { 43 | htab_entry item; 44 | size_t hash; 45 | }; 46 | 47 | struct htab { 48 | struct elem *elems; 49 | size_t mask; 50 | size_t used; 51 | }; 52 | 53 | #define MINSIZE 8 54 | #define MAXSIZE ((size_t)-1/2 + 1) 55 | 56 | static size_t keyhash(char *k) 57 | { 58 | unsigned char *p = (void *)k; 59 | size_t h = 0; 60 | 61 | while (*p) 62 | h = 31*h + *p++; 63 | return h; 64 | } 65 | 66 | static int resize(struct htab *htab, size_t nel) 67 | { 68 | size_t newsize; 69 | size_t i, j; 70 | struct elem *e, *newe; 71 | struct elem *oldtab = htab->elems; 72 | struct elem *oldend = htab->elems + htab->mask + 1; 73 | 74 | if (nel > MAXSIZE) 75 | nel = MAXSIZE; 76 | for (newsize = MINSIZE; newsize < nel; newsize *= 2); 77 | htab->elems = calloc(newsize, sizeof *htab->elems); 78 | if (!htab->elems) { 79 | htab->elems = oldtab; 80 | return 0; 81 | } 82 | htab->mask = newsize - 1; 83 | if (!oldtab) 84 | return 1; 85 | for (e = oldtab; e < oldend; e++) 86 | if (e->item.key) { 87 | for (i=e->hash,j=1; ; i+=j++) { 88 | newe = htab->elems + (i & htab->mask); 89 | if (!newe->item.key) 90 | break; 91 | } 92 | *newe = *e; 93 | } 94 | free(oldtab); 95 | return 1; 96 | } 97 | 98 | static struct elem *lookup(struct htab *htab, char *key, size_t hash) 99 | { 100 | size_t i, j; 101 | struct elem *e; 102 | 103 | for (i=hash,j=1; ; i+=j++) { 104 | e = htab->elems + (i & htab->mask); 105 | if (!e->item.key || 106 | (e->hash==hash && strcmp(e->item.key, key)==0)) 107 | break; 108 | } 109 | return e; 110 | } 111 | 112 | struct htab *htab_create(size_t nel) 113 | { 114 | struct htab *r = calloc(1, sizeof *r); 115 | if(r && !resize(r, nel)) { 116 | free(r); 117 | r = 0; 118 | } 119 | return r; 120 | } 121 | 122 | void htab_destroy(struct htab *htab) 123 | { 124 | free(htab->elems); 125 | free(htab); 126 | } 127 | 128 | static htab_entry *htab_find_item(struct htab *htab, char* key) 129 | { 130 | size_t hash = keyhash(key); 131 | struct elem *e = lookup(htab, key, hash); 132 | 133 | if (e->item.key) { 134 | return &e->item; 135 | } 136 | return 0; 137 | } 138 | 139 | htab_value* htab_find(struct htab *htab, char* key) 140 | { 141 | htab_entry *i = htab_find_item(htab, key); 142 | if(i) return &i->data; 143 | return 0; 144 | } 145 | 146 | int htab_delete(struct htab *htab, char* key) 147 | { 148 | htab_entry *i = htab_find_item(htab, key); 149 | if(!i) return 0; 150 | i->key = 0; 151 | return 1; 152 | } 153 | 154 | int htab_insert(struct htab *htab, char* key, htab_value value) 155 | { 156 | size_t hash = keyhash(key); 157 | struct elem *e = lookup(htab, key, hash); 158 | if(e->item.key) { 159 | /* it's not allowed to overwrite existing data */ 160 | return 0; 161 | } 162 | 163 | e->item.key = key; 164 | e->item.data = value; 165 | e->hash = hash; 166 | if (++htab->used > htab->mask - htab->mask/4) { 167 | if (!resize(htab, 2*htab->used)) { 168 | htab->used--; 169 | e->item.key = 0; 170 | return 0; 171 | } 172 | } 173 | return 1; 174 | } 175 | 176 | size_t htab_next(struct htab *htab, size_t iterator, char** key, htab_value **v) 177 | { 178 | size_t i; 179 | for(i=iterator;imask+1;++i) { 180 | struct elem *e = htab->elems + i; 181 | if(e->item.key) { 182 | *key = e->item.key; 183 | *v = &e->item.data; 184 | return i+1; 185 | } 186 | } 187 | return 0; 188 | } 189 | -------------------------------------------------------------------------------- /src/daemon/hsearch.h: -------------------------------------------------------------------------------- 1 | #ifndef HSEARCH_H 2 | #define HSEARCH_H 3 | 4 | #include 5 | 6 | typedef union htab_value { 7 | void *p; 8 | size_t n; 9 | } htab_value; 10 | 11 | #define HTV_N(N) (htab_value) {.n = N} 12 | #define HTV_P(P) (htab_value) {.p = P} 13 | 14 | struct htab * htab_create(size_t); 15 | void htab_destroy(struct htab *); 16 | htab_value* htab_find(struct htab *, char* key); 17 | int htab_insert(struct htab *, char*, htab_value); 18 | int htab_delete(struct htab *htab, char* key); 19 | size_t htab_next(struct htab *, size_t iterator, char** key, htab_value **v); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/daemon/sblist.c: -------------------------------------------------------------------------------- 1 | #undef _POSIX_C_SOURCE 2 | #define _POSIX_C_SOURCE 200809L 3 | #include "sblist.h" 4 | #include 5 | #include 6 | #include 7 | #define MY_PAGE_SIZE 4096 8 | 9 | sblist* sblist_new(size_t itemsize, size_t blockitems) { 10 | sblist* ret = (sblist*) malloc(sizeof(sblist)); 11 | sblist_init(ret, itemsize, blockitems); 12 | return ret; 13 | } 14 | 15 | static void sblist_clear(sblist* l) { 16 | l->items = NULL; 17 | l->capa = 0; 18 | l->count = 0; 19 | } 20 | 21 | void sblist_init(sblist* l, size_t itemsize, size_t blockitems) { 22 | if(l) { 23 | l->blockitems = blockitems ? blockitems : MY_PAGE_SIZE / itemsize; 24 | l->itemsize = itemsize; 25 | sblist_clear(l); 26 | } 27 | } 28 | 29 | void sblist_free_items(sblist* l) { 30 | if(l) { 31 | if(l->items) free(l->items); 32 | sblist_clear(l); 33 | } 34 | } 35 | 36 | void sblist_free(sblist* l) { 37 | if(l) { 38 | sblist_free_items(l); 39 | free(l); 40 | } 41 | } 42 | 43 | char* sblist_item_from_index(sblist* l, size_t idx) { 44 | return l->items + (idx * l->itemsize); 45 | } 46 | 47 | void* sblist_get(sblist* l, size_t item) { 48 | if(item < l->count) return (void*) sblist_item_from_index(l, item); 49 | return NULL; 50 | } 51 | 52 | int sblist_set(sblist* l, void* item, size_t pos) { 53 | if(pos >= l->count) return 0; 54 | memcpy(sblist_item_from_index(l, pos), item, l->itemsize); 55 | return 1; 56 | } 57 | 58 | int sblist_grow_if_needed(sblist* l) { 59 | char* temp; 60 | if(l->count == l->capa) { 61 | temp = realloc(l->items, (l->capa + l->blockitems) * l->itemsize); 62 | if(!temp) return 0; 63 | l->capa += l->blockitems; 64 | l->items = temp; 65 | } 66 | return 1; 67 | } 68 | 69 | int sblist_add(sblist* l, void* item) { 70 | if(!sblist_grow_if_needed(l)) return 0; 71 | l->count++; 72 | return sblist_set(l, item, l->count - 1); 73 | } 74 | -------------------------------------------------------------------------------- /src/daemon/sblist.h: -------------------------------------------------------------------------------- 1 | #ifndef SBLIST_H 2 | #define SBLIST_H 3 | 4 | /* this file is part of libulz, as of commit 8ab361a27743aaf025323ee43b8b8876dc054fdd 5 | modified for direct inclusion in microsocks. */ 6 | 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #include 13 | /* 14 | * simple buffer list. 15 | * 16 | * this thing here is basically a generic dynamic array 17 | * will realloc after every blockitems inserts 18 | * can store items of any size. 19 | * 20 | * so think of it as a by-value list, as opposed to a typical by-ref list. 21 | * you typically use it by having some struct on the stack, and pass a pointer 22 | * to sblist_add, which will copy the contents into its internal memory. 23 | * 24 | */ 25 | 26 | typedef struct { 27 | size_t itemsize; 28 | size_t blockitems; 29 | size_t count; 30 | size_t capa; 31 | char* items; 32 | } sblist; 33 | 34 | #define sblist_getsize(X) ((X)->count) 35 | #define sblist_get_count(X) ((X)->count) 36 | #define sblist_empty(X) ((X)->count == 0) 37 | 38 | // for dynamic style 39 | sblist* sblist_new(size_t itemsize, size_t blockitems); 40 | void sblist_free(sblist* l); 41 | 42 | //for static style 43 | void sblist_init(sblist* l, size_t itemsize, size_t blockitems); 44 | void sblist_free_items(sblist* l); 45 | 46 | // accessors 47 | void* sblist_get(sblist* l, size_t item); 48 | // returns 1 on success, 0 on OOM 49 | int sblist_add(sblist* l, void* item); 50 | int sblist_set(sblist* l, void* item, size_t pos); 51 | void sblist_delete(sblist* l, size_t item); 52 | char* sblist_item_from_index(sblist* l, size_t idx); 53 | int sblist_grow_if_needed(sblist* l); 54 | int sblist_insert(sblist* l, void* item, size_t pos); 55 | /* same as sblist_add, but returns list index of new item, or -1 */ 56 | size_t sblist_addi(sblist* l, void* item); 57 | void sblist_sort(sblist *l, int (*compar)(const void *, const void *)); 58 | /* insert element into presorted list, returns listindex of new entry or -1*/ 59 | size_t sblist_insert_sorted(sblist* l, void* o, int (*compar)(const void *, const void *)); 60 | 61 | #ifndef __COUNTER__ 62 | #define __COUNTER__ __LINE__ 63 | #endif 64 | 65 | #define __sblist_concat_impl( x, y ) x##y 66 | #define __sblist_macro_concat( x, y ) __sblist_concat_impl( x, y ) 67 | #define __sblist_iterator_name __sblist_macro_concat(sblist_iterator, __COUNTER__) 68 | 69 | // use with custom iterator variable 70 | #define sblist_iter_counter(LIST, ITER, PTR) \ 71 | for(size_t ITER = 0; (PTR = sblist_get(LIST, ITER)), ITER < sblist_getsize(LIST); ITER++) 72 | 73 | // use with custom iterator variable, which is predeclared 74 | #define sblist_iter_counter2(LIST, ITER, PTR) \ 75 | for(ITER = 0; (PTR = sblist_get(LIST, ITER)), ITER < sblist_getsize(LIST); ITER++) 76 | 77 | // use with custom iterator variable, which is predeclared and signed 78 | // useful for a loop which can delete items from the list, and then decrease the iterator var. 79 | #define sblist_iter_counter2s(LIST, ITER, PTR) \ 80 | for(ITER = 0; (PTR = sblist_get(LIST, ITER)), ITER < (ssize_t) sblist_getsize(LIST); ITER++) 81 | 82 | 83 | // uses "magic" iterator variable 84 | #define sblist_iter(LIST, PTR) sblist_iter_counter(LIST, __sblist_iterator_name, PTR) 85 | 86 | #ifdef __cplusplus 87 | } 88 | #endif 89 | 90 | #pragma RcB2 DEP "sblist.c" "sblist_delete.c" 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /src/daemon/sblist_delete.c: -------------------------------------------------------------------------------- 1 | #include "sblist.h" 2 | #include 3 | 4 | void sblist_delete(sblist* l, size_t item) { 5 | if (l->count && item < l->count) { 6 | memmove(sblist_item_from_index(l, item), sblist_item_from_index(l, item + 1), (sblist_getsize(l) - (item + 1)) * l->itemsize); 7 | l->count--; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/daemon/udpclient.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../remotedns.h" 9 | #include "../ip_type.h" 10 | 11 | int main() { 12 | int fd; 13 | int port = 1053; 14 | char srvn[] = "127.0.0.1"; 15 | struct sockaddr_in srva = {.sin_family = AF_INET, .sin_port = htons(port)}; 16 | inet_pton(AF_INET, srvn, &srva.sin_addr); 17 | fd = socket(AF_INET, SOCK_DGRAM, 0); 18 | char namebuf[260]; 19 | while(fgets(namebuf, sizeof namebuf, stdin)) { 20 | size_t l = strlen(namebuf); 21 | if(namebuf[l-1] == '\n') { 22 | l--; 23 | namebuf[l] = 0; 24 | } 25 | struct at_msg msg = {0}; 26 | unsigned msglen; 27 | if(isdigit(namebuf[0])) { 28 | msglen = 4; 29 | msg.h.msgtype = ATM_GETNAME; 30 | inet_aton(namebuf, (void*) &msg.m.ip); 31 | } else { 32 | msglen = l+1; 33 | msg.h.msgtype = ATM_GETIP; 34 | memcpy(msg.m.host, namebuf, msglen); 35 | } 36 | msg.h.datalen = htons(msglen); 37 | sendto(fd, &msg, sizeof(msg.h)+msglen, 0, (void*)&srva, sizeof(srva)); 38 | char rcvbuf[512]; 39 | recvfrom(fd, rcvbuf, sizeof rcvbuf, 0, (void*)0, (void*)0); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/daemon/udpserver.c: -------------------------------------------------------------------------------- 1 | #include "udpserver.h" 2 | #include 3 | #include 4 | #include 5 | 6 | int resolve(const char *host, unsigned short port, struct addrinfo** addr) { 7 | struct addrinfo hints = { 8 | .ai_family = AF_UNSPEC, 9 | .ai_socktype = SOCK_STREAM, 10 | .ai_flags = AI_PASSIVE, 11 | }; 12 | char port_buf[8]; 13 | snprintf(port_buf, sizeof port_buf, "%u", port); 14 | return getaddrinfo(host, port_buf, &hints, addr); 15 | } 16 | 17 | int resolve_sa(const char *host, unsigned short port, union sockaddr_union *res) { 18 | struct addrinfo *ainfo = 0; 19 | int ret; 20 | SOCKADDR_UNION_AF(res) = AF_UNSPEC; 21 | if((ret = resolve(host, port, &ainfo))) return ret; 22 | memcpy(res, ainfo->ai_addr, ainfo->ai_addrlen); 23 | freeaddrinfo(ainfo); 24 | return 0; 25 | } 26 | 27 | int bindtoip(int fd, union sockaddr_union *bindaddr) { 28 | socklen_t sz = SOCKADDR_UNION_LENGTH(bindaddr); 29 | if(sz) 30 | return bind(fd, (struct sockaddr*) bindaddr, sz); 31 | return 0; 32 | } 33 | 34 | int server_waitclient(struct server *server, struct client* client, void* buf, size_t *buflen) { 35 | socklen_t clen = sizeof client->addr; 36 | ssize_t ret = recvfrom(server->fd, buf, *buflen, 0, (void*)&client->addr, &clen); 37 | if(ret >= 0) { 38 | *buflen = ret; 39 | return 0; 40 | } 41 | return ret; 42 | } 43 | 44 | int server_setup(struct server *server, const char* listenip, unsigned short port) { 45 | struct addrinfo *ainfo = 0; 46 | if(resolve(listenip, port, &ainfo)) return -1; 47 | struct addrinfo* p; 48 | int listenfd = -1; 49 | for(p = ainfo; p; p = p->ai_next) { 50 | if((listenfd = socket(p->ai_family, SOCK_DGRAM, 0)) < 0) 51 | continue; 52 | int yes = 1; 53 | setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); 54 | if(bind(listenfd, p->ai_addr, p->ai_addrlen) < 0) { 55 | close(listenfd); 56 | listenfd = -1; 57 | continue; 58 | } 59 | break; 60 | } 61 | freeaddrinfo(ainfo); 62 | if(listenfd < 0) return -2; 63 | server->fd = listenfd; 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /src/daemon/udpserver.h: -------------------------------------------------------------------------------- 1 | #ifndef SERVER_H 2 | #define SERVER_H 3 | 4 | #undef _POSIX_C_SOURCE 5 | #define _POSIX_C_SOURCE 200809L 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #pragma RcB2 DEP "udpserver.c" 12 | 13 | union sockaddr_union { 14 | struct sockaddr_in v4; 15 | struct sockaddr_in6 v6; 16 | }; 17 | 18 | #define SOCKADDR_UNION_AF(PTR) (PTR)->v4.sin_family 19 | 20 | #define SOCKADDR_UNION_LENGTH(PTR) ( \ 21 | ( SOCKADDR_UNION_AF(PTR) == AF_INET ) ? sizeof((PTR)->v4) : ( \ 22 | ( SOCKADDR_UNION_AF(PTR) == AF_INET6 ) ? sizeof((PTR)->v6) : 0 ) ) 23 | 24 | #define SOCKADDR_UNION_ADDRESS(PTR) ( \ 25 | ( SOCKADDR_UNION_AF(PTR) == AF_INET ) ? (void*) &(PTR)->v4.sin_addr : ( \ 26 | ( SOCKADDR_UNION_AF(PTR) == AF_INET6 ) ? (void*) &(PTR)->v6.sin6_addr : (void*) 0 ) ) 27 | 28 | #define SOCKADDR_UNION_PORT(PTR) ( \ 29 | ( SOCKADDR_UNION_AF(PTR) == AF_INET ) ? (PTR)->v4.sin_port : ( \ 30 | ( SOCKADDR_UNION_AF(PTR) == AF_INET6 ) ? (PTR)->v6.sin6_port : 0 ) ) 31 | 32 | struct client { 33 | union sockaddr_union addr; 34 | }; 35 | 36 | struct server { 37 | int fd; 38 | }; 39 | 40 | int resolve(const char *host, unsigned short port, struct addrinfo** addr); 41 | int resolve_sa(const char *host, unsigned short port, union sockaddr_union *res); 42 | int bindtoip(int fd, union sockaddr_union *bindaddr); 43 | 44 | int server_waitclient(struct server *server, struct client* client, void* buf, size_t *buflen); 45 | int server_setup(struct server *server, const char* listenip, unsigned short port); 46 | 47 | #endif 48 | 49 | -------------------------------------------------------------------------------- /src/debug.c: -------------------------------------------------------------------------------- 1 | 2 | #ifdef DEBUG 3 | # include "core.h" 4 | # include "common.h" 5 | # include "debug.h" 6 | #include 7 | 8 | void dump_proxy_chain(proxy_data *pchain, unsigned int count) { 9 | char ip_buf[INET6_ADDRSTRLEN]; 10 | for (; count; pchain++, count--) { 11 | if(!inet_ntop(pchain->ip.is_v6?AF_INET6:AF_INET,pchain->ip.addr.v6,ip_buf,sizeof ip_buf)) { 12 | proxychains_write_log(LOG_PREFIX "error: ip address conversion failed\n"); 13 | continue; 14 | } 15 | PDEBUG("[%s] %s %s:%d", proxy_state_strmap[pchain->ps], 16 | proxy_type_strmap[pchain->pt], 17 | ip_buf, htons(pchain->port)); 18 | if (*pchain->user || *pchain->pass) { 19 | PSTDERR(" [u=%s,p=%s]", pchain->user, pchain->pass); 20 | } 21 | PSTDERR("\n"); 22 | } 23 | } 24 | 25 | #else 26 | 27 | // Do not allow this translation unit to end up empty 28 | // for non-DEBUG builds, to satisfy ISO C standards. 29 | typedef int __appease_iso_compilers__; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/debug.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUG_H 2 | #define DEBUG_H 3 | 4 | # include 5 | 6 | #ifdef DEBUG 7 | # define PSTDERR(fmt, args...) do { dprintf(2,fmt, ## args); } while(0) 8 | # define PDEBUG(fmt, args...) PSTDERR("DEBUG:pid[%d]:" fmt, getpid(), ## args) 9 | # define DEBUGDECL(args...) args 10 | # define DUMP_PROXY_CHAIN(A, B) dump_proxy_chain(A, B) 11 | #else 12 | # define PDEBUG(fmt, args...) do {} while (0) 13 | # define DEBUGDECL(args...) 14 | # define DUMP_PROXY_CHAIN(args...) do {} while (0) 15 | #endif 16 | 17 | # define PFUNC() do { PDEBUG("%s()\n", __FUNCTION__); } while(0) 18 | 19 | #include "core.h" 20 | void dump_proxy_chain(proxy_data *pchain, unsigned int count); 21 | 22 | 23 | #endif 24 | 25 | -------------------------------------------------------------------------------- /src/hash.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | 3 | /* dalias' version of the elf hash */ 4 | uint32_t dalias_hash(char *s0) { 5 | unsigned char *s = (void *) s0; 6 | uint_fast32_t h = 0; 7 | while(*s) { 8 | h = 16 * h + *s++; 9 | h ^= h >> 24 & 0xf0; 10 | } 11 | return h & 0xfffffff; 12 | } 13 | -------------------------------------------------------------------------------- /src/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef HASH_H 2 | #define HASH_H 3 | 4 | #include 5 | 6 | uint32_t dalias_hash(char *s0); 7 | 8 | //RcB: DEP "hash.c" 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/hostsreader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "common.h" 5 | 6 | /* 7 | simple reader for /etc/hosts 8 | it only supports comments, blank lines and lines consisting of an ipv4 hostname pair. 9 | this is required so we can return entries from the host db without messing up the 10 | non-thread-safe state of libc's gethostent(). 11 | 12 | */ 13 | 14 | struct hostsreader { 15 | FILE *f; 16 | char* ip, *name; 17 | }; 18 | 19 | int hostsreader_open(struct hostsreader *ctx) { 20 | if(!(ctx->f = fopen("/etc/hosts", "r"))) return 0; 21 | return 1; 22 | } 23 | 24 | void hostsreader_close(struct hostsreader *ctx) { 25 | fclose(ctx->f); 26 | } 27 | 28 | int hostsreader_get(struct hostsreader *ctx, char* buf, size_t bufsize) { 29 | while(1) { 30 | if(!fgets(buf, bufsize, ctx->f)) return 0; 31 | if(*buf == '#') continue; 32 | char *p = buf; 33 | size_t l = bufsize; 34 | ctx->ip = p; 35 | while(*p && !isspace(*p) && l) { 36 | p++; 37 | l--; 38 | } 39 | if(!l || !*p || p == ctx->ip) continue; 40 | *p = 0; 41 | p++; 42 | while(*p && isspace(*p) && l) { 43 | p++; 44 | l--; 45 | } 46 | if(!l || !*p) continue; 47 | ctx->name = p; 48 | while(*p && !isspace(*p) && l) { 49 | p++; 50 | l--; 51 | } 52 | if(!l || !*p) continue; 53 | *p = 0; 54 | if(pc_isnumericipv4(ctx->ip)) return 1; 55 | } 56 | } 57 | 58 | char* hostsreader_get_ip_for_name(const char* name, char* buf, size_t bufsize) { 59 | struct hostsreader ctx; 60 | char *res = 0; 61 | if(!hostsreader_open(&ctx)) return 0; 62 | while(hostsreader_get(&ctx, buf, bufsize)) { 63 | if(!strcmp(ctx.name, name)) { 64 | res = ctx.ip; 65 | break; 66 | } 67 | } 68 | hostsreader_close(&ctx); 69 | return res; 70 | } 71 | 72 | #include "ip_type.h" 73 | #include 74 | #include 75 | #include 76 | ip_type4 hostsreader_get_numeric_ip_for_name(const char* name) { 77 | char *hres; 78 | char buf[320]; 79 | if((hres = hostsreader_get_ip_for_name(name, buf, sizeof buf))) { 80 | struct in_addr c; 81 | inet_aton(hres, &c); 82 | ip_type4 res; 83 | memcpy(res.octet, &c.s_addr, 4); 84 | return res; 85 | } else return IPT4_INVALID; 86 | } 87 | 88 | #ifdef HOSTSREADER_TEST 89 | #include "ip_type.c" 90 | int main(int a, char**b) { 91 | char buf[256]; 92 | if(a != 2) return 1; 93 | char * ret = hostsreader_get_ip_for_name(b[1], buf, sizeof buf); 94 | printf("%s\n", ret ? ret : "null"); 95 | } 96 | #endif 97 | -------------------------------------------------------------------------------- /src/ip_type.h: -------------------------------------------------------------------------------- 1 | #ifndef IP_TYPE_H 2 | #define IP_TYPE_H 3 | 4 | #include 5 | 6 | typedef union { 7 | unsigned char octet[4]; 8 | uint32_t as_int; 9 | } ip_type4; 10 | 11 | typedef struct { 12 | union { 13 | ip_type4 v4; 14 | unsigned char v6[16]; 15 | } addr; 16 | char is_v6; 17 | } ip_type; 18 | 19 | #define IPT4_INT(X) (ip_type4){.as_int = (X)} 20 | #define IPT4_INVALID IPT4_INT(-1) 21 | 22 | #define IPT4_BYTES(A,B,C,D) (ip_type4){.octet = {(A), (B), (C), (D)} } 23 | #define IPT4_LOCALHOST IPT4_BYTES(127,0,0,1) 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/libproxychains.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | libproxychains.c - description 3 | ------------------- 4 | begin : Tue May 14 2002 5 | copyright : netcreature (C) 2002 6 | email : netcreature@users.sourceforge.net 7 | ***************************************************************************/ 8 | /* GPL */ 9 | /*************************************************************************** 10 | * * 11 | * This program is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU General Public License as published by * 13 | * the Free Software Foundation; either version 2 of the License, or * 14 | * (at your option) any later version. * 15 | * * 16 | ***************************************************************************/ 17 | 18 | #undef _GNU_SOURCE 19 | #define _GNU_SOURCE 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | 40 | #include "core.h" 41 | #include "common.h" 42 | #include "rdns.h" 43 | 44 | #undef satosin 45 | #define satosin(x) ((struct sockaddr_in *) &(x)) 46 | #define SOCKADDR(x) (satosin(x)->sin_addr.s_addr) 47 | #define SOCKADDR_2(x) (satosin(x)->sin_addr) 48 | #define SOCKPORT(x) (satosin(x)->sin_port) 49 | #define SOCKFAMILY(x) (satosin(x)->sin_family) 50 | #define MAX_CHAIN 512 51 | 52 | #ifdef IS_SOLARIS 53 | #undef connect 54 | int __xnet_connect(int sock, const struct sockaddr *addr, unsigned int len); 55 | connect_t true___xnet_connect; 56 | #endif 57 | 58 | close_t true_close; 59 | close_range_t true_close_range; 60 | connect_t true_connect; 61 | gethostbyname_t true_gethostbyname; 62 | getaddrinfo_t true_getaddrinfo; 63 | freeaddrinfo_t true_freeaddrinfo; 64 | getnameinfo_t true_getnameinfo; 65 | gethostbyaddr_t true_gethostbyaddr; 66 | sendto_t true_sendto; 67 | 68 | int tcp_read_time_out; 69 | int tcp_connect_time_out; 70 | chain_type proxychains_ct; 71 | proxy_data proxychains_pd[MAX_CHAIN]; 72 | unsigned int proxychains_proxy_count = 0; 73 | unsigned int proxychains_proxy_offset = 0; 74 | int proxychains_got_chain_data = 0; 75 | unsigned int proxychains_max_chain = 1; 76 | int proxychains_quiet_mode = 0; 77 | enum dns_lookup_flavor proxychains_resolver = DNSLF_LIBC; 78 | localaddr_arg localnet_addr[MAX_LOCALNET]; 79 | size_t num_localnet_addr = 0; 80 | dnat_arg dnats[MAX_DNAT]; 81 | size_t num_dnats = 0; 82 | unsigned int remote_dns_subnet = 224; 83 | 84 | pthread_once_t init_once = PTHREAD_ONCE_INIT; 85 | 86 | static int init_l = 0; 87 | 88 | static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_type * ct); 89 | 90 | static void* load_sym(char* symname, void* proxyfunc, int is_mandatory) { 91 | void *funcptr = dlsym(RTLD_NEXT, symname); 92 | 93 | if(is_mandatory && !funcptr) { 94 | fprintf(stderr, "Cannot load symbol '%s' %s\n", symname, dlerror()); 95 | exit(1); 96 | } else if (!funcptr) { 97 | return funcptr; 98 | } else { 99 | PDEBUG("loaded symbol '%s'" " real addr %p wrapped addr %p\n", symname, funcptr, proxyfunc); 100 | } 101 | if(funcptr == proxyfunc) { 102 | PDEBUG("circular reference detected, aborting!\n"); 103 | abort(); 104 | } 105 | return funcptr; 106 | } 107 | 108 | #include "allocator_thread.h" 109 | 110 | const char *proxychains_get_version(void); 111 | 112 | static void setup_hooks(void); 113 | 114 | typedef struct { 115 | unsigned int first, last, flags; 116 | } close_range_args_t; 117 | 118 | /* If there is some `close` or `close_range` system call before do_init, 119 | we buffer it, and actually execute them in do_init. */ 120 | static int close_fds[16]; 121 | static int close_fds_cnt = 0; 122 | static close_range_args_t close_range_buffer[16]; 123 | static int close_range_buffer_cnt = 0; 124 | 125 | static unsigned get_rand_seed(void) { 126 | #ifdef HAVE_CLOCK_GETTIME 127 | struct timespec now; 128 | clock_gettime(CLOCK_REALTIME, &now); 129 | return now.tv_sec ^ now.tv_nsec; 130 | #else 131 | return time(NULL); 132 | #endif 133 | } 134 | 135 | static void do_init(void) { 136 | char *env; 137 | 138 | srand(get_rand_seed()); 139 | core_initialize(); 140 | 141 | env = getenv(PROXYCHAINS_QUIET_MODE_ENV_VAR); 142 | if(env && *env == '1') 143 | proxychains_quiet_mode = 1; 144 | 145 | proxychains_write_log(LOG_PREFIX "DLL init: proxychains-ng %s\n", proxychains_get_version()); 146 | 147 | setup_hooks(); 148 | 149 | /* read the config file */ 150 | get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct); 151 | DUMP_PROXY_CHAIN(proxychains_pd, proxychains_proxy_count); 152 | 153 | while(close_fds_cnt) true_close(close_fds[--close_fds_cnt]); 154 | while(close_range_buffer_cnt) { 155 | int i = --close_range_buffer_cnt; 156 | true_close_range(close_range_buffer[i].first, close_range_buffer[i].last, close_range_buffer[i].flags); 157 | } 158 | init_l = 1; 159 | 160 | rdns_init(proxychains_resolver); 161 | } 162 | 163 | static void init_lib_wrapper(const char* caller) { 164 | #ifndef DEBUG 165 | (void) caller; 166 | #endif 167 | if(!init_l) PDEBUG("%s called from %s\n", __FUNCTION__, caller); 168 | pthread_once(&init_once, do_init); 169 | } 170 | 171 | /* if we use gcc >= 3, we can instruct the dynamic loader 172 | * to call init_lib at link time. otherwise it gets loaded 173 | * lazily, which has the disadvantage that there's a potential 174 | * race condition if 2 threads call it before init_l is set 175 | * and PTHREAD support was disabled */ 176 | #if __GNUC__+0 > 2 177 | __attribute__((constructor)) 178 | static void gcc_init(void) { 179 | init_lib_wrapper(__FUNCTION__); 180 | } 181 | #define INIT() do {} while(0) 182 | #else 183 | #define INIT() init_lib_wrapper(__FUNCTION__) 184 | #endif 185 | 186 | 187 | typedef enum { 188 | RS_PT_NONE = 0, 189 | RS_PT_SOCKS4, 190 | RS_PT_SOCKS5, 191 | RS_PT_HTTP 192 | } rs_proxyType; 193 | 194 | /* 195 | proxy_from_string() taken from rocksock network I/O library (C) rofl0r 196 | valid inputs: 197 | socks5://user:password@proxy.domain.com:port 198 | socks5://proxy.domain.com:port 199 | socks4://proxy.domain.com:port 200 | http://user:password@proxy.domain.com:port 201 | http://proxy.domain.com:port 202 | 203 | supplying port number is obligatory. 204 | user:pass@ part is optional for http and socks5. 205 | however, user:pass authentication is currently not implemented for http proxies. 206 | return 1 on success, 0 on error. 207 | */ 208 | static int proxy_from_string(const char *proxystring, 209 | char *type_buf, 210 | char* host_buf, 211 | int *port_n, 212 | char *user_buf, 213 | char* pass_buf) 214 | { 215 | const char* p; 216 | rs_proxyType proxytype; 217 | 218 | size_t next_token = 6, ul = 0, pl = 0, hl; 219 | if(!proxystring[0] || !proxystring[1] || !proxystring[2] || !proxystring[3] || !proxystring[4] || !proxystring[5]) goto inv_string; 220 | if(*proxystring == 's') { 221 | switch(proxystring[5]) { 222 | case '5': proxytype = RS_PT_SOCKS5; break; 223 | case '4': proxytype = RS_PT_SOCKS4; break; 224 | default: goto inv_string; 225 | } 226 | } else if(*proxystring == 'h') { 227 | proxytype = RS_PT_HTTP; 228 | next_token = 4; 229 | } else goto inv_string; 230 | if( 231 | proxystring[next_token++] != ':' || 232 | proxystring[next_token++] != '/' || 233 | proxystring[next_token++] != '/') goto inv_string; 234 | const char *at = strrchr(proxystring+next_token, '@'); 235 | if(at) { 236 | if(proxytype == RS_PT_SOCKS4) 237 | return 0; 238 | p = strchr(proxystring+next_token, ':'); 239 | if(!p || p >= at) goto inv_string; 240 | const char *u = proxystring+next_token; 241 | ul = p-u; 242 | p++; 243 | pl = at-p; 244 | if(proxytype == RS_PT_SOCKS5 && (ul > 255 || pl > 255)) 245 | return 0; 246 | memcpy(user_buf, u, ul); 247 | user_buf[ul]=0; 248 | memcpy(pass_buf, p, pl); 249 | pass_buf[pl]=0; 250 | next_token += 2+ul+pl; 251 | } else { 252 | user_buf[0]=0; 253 | pass_buf[0]=0; 254 | } 255 | const char* h = proxystring+next_token; 256 | p = strchr(h, ':'); 257 | if(!p) goto inv_string; 258 | hl = p-h; 259 | if(hl > 255) 260 | return 0; 261 | memcpy(host_buf, h, hl); 262 | host_buf[hl]=0; 263 | *port_n = atoi(p+1); 264 | switch(proxytype) { 265 | case RS_PT_SOCKS4: 266 | strcpy(type_buf, "socks4"); 267 | break; 268 | case RS_PT_SOCKS5: 269 | strcpy(type_buf, "socks5"); 270 | break; 271 | case RS_PT_HTTP: 272 | strcpy(type_buf, "http"); 273 | break; 274 | default: 275 | return 0; 276 | } 277 | return 1; 278 | inv_string: 279 | return 0; 280 | } 281 | 282 | static const char* bool_str(int bool_val) { 283 | if(bool_val) return "true"; 284 | return "false"; 285 | } 286 | 287 | #define STR_STARTSWITH(P, LIT) (!strncmp(P, LIT, sizeof(LIT)-1)) 288 | /* get configuration from config file */ 289 | static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_type * ct) { 290 | int count = 0, port_n = 0, list = 0; 291 | char buf[1024], type[1024], host[1024], user[1024]; 292 | char *buff, *env, *p; 293 | char local_addr_port[64], local_addr[64], local_netmask[32]; 294 | char dnat_orig_addr_port[32], dnat_new_addr_port[32]; 295 | char dnat_orig_addr[32], dnat_orig_port[32], dnat_new_addr[32], dnat_new_port[32]; 296 | char rdnsd_addr[32], rdnsd_port[8]; 297 | FILE *file = NULL; 298 | 299 | if(proxychains_got_chain_data) 300 | return; 301 | 302 | PFUNC(); 303 | 304 | //Some defaults 305 | tcp_read_time_out = 4 * 1000; 306 | tcp_connect_time_out = 10 * 1000; 307 | *ct = DYNAMIC_TYPE; 308 | 309 | env = get_config_path(getenv(PROXYCHAINS_CONF_FILE_ENV_VAR), buf, sizeof(buf)); 310 | if( ( file = fopen(env, "r") ) == NULL ) 311 | { 312 | perror("couldnt read configuration file"); 313 | exit(1); 314 | } 315 | 316 | while(fgets(buf, sizeof(buf), file)) { 317 | buff = buf; 318 | /* remove leading whitespace */ 319 | while(isspace(*buff)) buff++; 320 | /* remove trailing '\n' */ 321 | if((p = strrchr(buff, '\n'))) *p = 0; 322 | p = buff + strlen(buff)-1; 323 | /* remove trailing whitespace */ 324 | while(p >= buff && isspace(*p)) *(p--) = 0; 325 | if(!*buff || *buff == '#') continue; /* skip empty lines and comments */ 326 | if(1) { 327 | /* proxylist has to come last */ 328 | if(list) { 329 | if(count >= MAX_CHAIN) 330 | break; 331 | 332 | memset(&pd[count], 0, sizeof(proxy_data)); 333 | 334 | pd[count].ps = PLAY_STATE; 335 | port_n = 0; 336 | 337 | int ret = sscanf(buff, "%s %s %d %s %s", type, host, &port_n, pd[count].user, pd[count].pass); 338 | if(ret < 3 || ret == EOF) { 339 | if(!proxy_from_string(buff, type, host, &port_n, pd[count].user, pd[count].pass)) { 340 | inv: 341 | fprintf(stderr, "error: invalid item in proxylist section: %s", buff); 342 | exit(1); 343 | } 344 | } 345 | 346 | memset(&pd[count].ip, 0, sizeof(pd[count].ip)); 347 | pd[count].ip.is_v6 = !!strchr(host, ':'); 348 | pd[count].port = htons((unsigned short) port_n); 349 | ip_type* host_ip = &pd[count].ip; 350 | if(1 != inet_pton(host_ip->is_v6 ? AF_INET6 : AF_INET, host, host_ip->addr.v6)) { 351 | if(*ct == STRICT_TYPE && proxychains_resolver >= DNSLF_RDNS_START && count > 0) { 352 | /* we can allow dns hostnames for all but the first proxy in the list if chaintype is strict, as remote lookup can be done */ 353 | rdns_init(proxychains_resolver); 354 | ip_type4 internal_ip = rdns_get_ip_for_host(host, strlen(host)); 355 | pd[count].ip.is_v6 = 0; 356 | host_ip->addr.v4 = internal_ip; 357 | if(internal_ip.as_int == IPT4_INVALID.as_int) 358 | goto inv_host; 359 | } else { 360 | inv_host: 361 | fprintf(stderr, "proxy %s has invalid value or is not numeric\n", host); 362 | fprintf(stderr, "non-numeric ips are only allowed under the following circumstances:\n"); 363 | fprintf(stderr, "chaintype == strict (%s), proxy is not first in list (%s), proxy_dns active (%s)\n\n", bool_str(*ct == STRICT_TYPE), bool_str(count > 0), rdns_resolver_string(proxychains_resolver)); 364 | exit(1); 365 | } 366 | } 367 | 368 | if(!strcmp(type, "http")) { 369 | pd[count].pt = HTTP_TYPE; 370 | } else if(!strcmp(type, "raw")) { 371 | pd[count].pt = RAW_TYPE; 372 | } else if(!strcmp(type, "socks4")) { 373 | pd[count].pt = SOCKS4_TYPE; 374 | } else if(!strcmp(type, "socks5")) { 375 | pd[count].pt = SOCKS5_TYPE; 376 | } else 377 | goto inv; 378 | 379 | if(port_n) 380 | count++; 381 | } else { 382 | if(!strcmp(buff, "[ProxyList]")) { 383 | list = 1; 384 | } else if(!strcmp(buff, "random_chain")) { 385 | *ct = RANDOM_TYPE; 386 | } else if(!strcmp(buff, "strict_chain")) { 387 | *ct = STRICT_TYPE; 388 | } else if(!strcmp(buff, "dynamic_chain")) { 389 | *ct = DYNAMIC_TYPE; 390 | } else if(!strcmp(buff, "round_robin_chain")) { 391 | *ct = ROUND_ROBIN_TYPE; 392 | } else if(STR_STARTSWITH(buff, "tcp_read_time_out")) { 393 | sscanf(buff, "%s %d", user, &tcp_read_time_out); 394 | } else if(STR_STARTSWITH(buff, "tcp_connect_time_out")) { 395 | sscanf(buff, "%s %d", user, &tcp_connect_time_out); 396 | } else if(STR_STARTSWITH(buff, "remote_dns_subnet")) { 397 | sscanf(buff, "%s %u", user, &remote_dns_subnet); 398 | if(remote_dns_subnet >= 256) { 399 | fprintf(stderr, 400 | "remote_dns_subnet: invalid value. requires a number between 0 and 255.\n"); 401 | exit(1); 402 | } 403 | } else if(STR_STARTSWITH(buff, "localnet")) { 404 | char colon, extra, right_bracket[2]; 405 | unsigned short local_port = 0, local_prefix; 406 | int local_family, n, valid; 407 | if(sscanf(buff, "%s %53[^/]/%15s%c", user, local_addr_port, local_netmask, &extra) != 3) { 408 | fprintf(stderr, "localnet format error"); 409 | exit(1); 410 | } 411 | p = strchr(local_addr_port, ':'); 412 | if(!p || p == strrchr(local_addr_port, ':')) { 413 | local_family = AF_INET; 414 | n = sscanf(local_addr_port, "%15[^:]%c%5hu%c", local_addr, &colon, &local_port, &extra); 415 | valid = n == 1 || (n == 3 && colon == ':'); 416 | } else if(local_addr_port[0] == '[') { 417 | local_family = AF_INET6; 418 | n = sscanf(local_addr_port, "[%45[^][]%1[]]%c%5hu%c", local_addr, right_bracket, &colon, &local_port, &extra); 419 | valid = n == 2 || (n == 4 && colon == ':'); 420 | } else { 421 | local_family = AF_INET6; 422 | valid = sscanf(local_addr_port, "%45[^][]%c", local_addr, &extra) == 1; 423 | } 424 | if(!valid) { 425 | fprintf(stderr, "localnet address or port error\n"); 426 | exit(1); 427 | } 428 | if(local_port) { 429 | PDEBUG("added localnet: netaddr=%s, port=%u, netmask=%s\n", 430 | local_addr, local_port, local_netmask); 431 | } else { 432 | PDEBUG("added localnet: netaddr=%s, netmask=%s\n", 433 | local_addr, local_netmask); 434 | } 435 | if(num_localnet_addr < MAX_LOCALNET) { 436 | localnet_addr[num_localnet_addr].family = local_family; 437 | localnet_addr[num_localnet_addr].port = local_port; 438 | valid = 0; 439 | if (local_family == AF_INET) { 440 | valid = 441 | inet_pton(local_family, local_addr, 442 | &localnet_addr[num_localnet_addr].in_addr) > 0; 443 | } else if(local_family == AF_INET6) { 444 | valid = 445 | inet_pton(local_family, local_addr, 446 | &localnet_addr[num_localnet_addr].in6_addr) > 0; 447 | } 448 | if(!valid) { 449 | fprintf(stderr, "localnet address error\n"); 450 | exit(1); 451 | } 452 | if(local_family == AF_INET && strchr(local_netmask, '.')) { 453 | valid = 454 | inet_pton(local_family, local_netmask, 455 | &localnet_addr[num_localnet_addr].in_mask) > 0; 456 | } else { 457 | valid = sscanf(local_netmask, "%hu%c", &local_prefix, &extra) == 1; 458 | if (valid) { 459 | if(local_family == AF_INET && local_prefix <= 32) { 460 | localnet_addr[num_localnet_addr].in_mask.s_addr = 461 | htonl(0xFFFFFFFFu << (32u - local_prefix)); 462 | } else if(local_family == AF_INET6 && local_prefix <= 128) { 463 | localnet_addr[num_localnet_addr].in6_prefix = 464 | local_prefix; 465 | } else { 466 | valid = 0; 467 | } 468 | } 469 | } 470 | if(!valid) { 471 | fprintf(stderr, "localnet netmask error\n"); 472 | exit(1); 473 | } 474 | ++num_localnet_addr; 475 | } else { 476 | fprintf(stderr, "# of localnet exceed %d.\n", MAX_LOCALNET); 477 | } 478 | } else if(STR_STARTSWITH(buff, "chain_len")) { 479 | char *pc; 480 | int len; 481 | pc = strchr(buff, '='); 482 | if(!pc) { 483 | fprintf(stderr, "error: missing equals sign '=' in chain_len directive.\n"); 484 | exit(1); 485 | } 486 | len = atoi(++pc); 487 | proxychains_max_chain = (len ? len : 1); 488 | } else if(!strcmp(buff, "quiet_mode")) { 489 | proxychains_quiet_mode = 1; 490 | } else if(!strcmp(buff, "proxy_dns_old")) { 491 | proxychains_resolver = DNSLF_FORKEXEC; 492 | } else if(!strcmp(buff, "proxy_dns")) { 493 | proxychains_resolver = DNSLF_RDNS_THREAD; 494 | } else if(STR_STARTSWITH(buff, "proxy_dns_daemon")) { 495 | struct sockaddr_in rdns_server_buffer; 496 | 497 | if(sscanf(buff, "%s %15[^:]:%5s", user, rdnsd_addr, rdnsd_port) < 3) { 498 | fprintf(stderr, "proxy_dns_daemon format error\n"); 499 | exit(1); 500 | } 501 | rdns_server_buffer.sin_family = AF_INET; 502 | int error = inet_pton(AF_INET, rdnsd_addr, &rdns_server_buffer.sin_addr); 503 | if(error <= 0) { 504 | fprintf(stderr, "bogus proxy_dns_daemon address\n"); 505 | exit(1); 506 | } 507 | rdns_server_buffer.sin_port = htons(atoi(rdnsd_port)); 508 | proxychains_resolver = DNSLF_RDNS_DAEMON; 509 | rdns_set_daemon(&rdns_server_buffer); 510 | } else if(STR_STARTSWITH(buff, "dnat")) { 511 | if(sscanf(buff, "%s %21[^ ] %21s\n", user, dnat_orig_addr_port, dnat_new_addr_port) < 3) { 512 | fprintf(stderr, "dnat format error"); 513 | exit(1); 514 | } 515 | /* clean previously used buffer */ 516 | memset(dnat_orig_port, 0, sizeof(dnat_orig_port) / sizeof(dnat_orig_port[0])); 517 | memset(dnat_new_port, 0, sizeof(dnat_new_port) / sizeof(dnat_new_port[0])); 518 | 519 | (void)sscanf(dnat_orig_addr_port, "%15[^:]:%5s", dnat_orig_addr, dnat_orig_port); 520 | (void)sscanf(dnat_new_addr_port, "%15[^:]:%5s", dnat_new_addr, dnat_new_port); 521 | 522 | if(num_dnats < MAX_DNAT) { 523 | int error; 524 | error = 525 | inet_pton(AF_INET, dnat_orig_addr, 526 | &dnats[num_dnats].orig_dst); 527 | if(error <= 0) { 528 | fprintf(stderr, "dnat original destination address error\n"); 529 | exit(1); 530 | } 531 | 532 | error = 533 | inet_pton(AF_INET, dnat_new_addr, 534 | &dnats[num_dnats].new_dst); 535 | if(error <= 0) { 536 | fprintf(stderr, "dnat effective destination address error\n"); 537 | exit(1); 538 | } 539 | 540 | if(dnat_orig_port[0]) { 541 | dnats[num_dnats].orig_port = 542 | (short) atoi(dnat_orig_port); 543 | } else { 544 | dnats[num_dnats].orig_port = 0; 545 | } 546 | 547 | if(dnat_new_port[0]) { 548 | dnats[num_dnats].new_port = 549 | (short) atoi(dnat_new_port); 550 | } else { 551 | dnats[num_dnats].new_port = 0; 552 | } 553 | 554 | PDEBUG("added dnat: orig-dst=%s orig-port=%d new-dst=%s new-port=%d\n", dnat_orig_addr, dnats[num_dnats].orig_port, dnat_new_addr, dnats[num_dnats].new_port); 555 | ++num_dnats; 556 | } else { 557 | fprintf(stderr, "# of dnat exceed %d.\n", MAX_DNAT); 558 | } 559 | } 560 | } 561 | } 562 | } 563 | #ifndef BROKEN_FCLOSE 564 | fclose(file); 565 | #endif 566 | if(!count) { 567 | fprintf(stderr, "error: no valid proxy found in config\n"); 568 | exit(1); 569 | } 570 | *proxy_count = count; 571 | proxychains_got_chain_data = 1; 572 | PDEBUG("proxy_dns: %s\n", rdns_resolver_string(proxychains_resolver)); 573 | } 574 | 575 | /******* HOOK FUNCTIONS *******/ 576 | 577 | #define EXPAND( args...) args 578 | #ifdef MONTEREY_HOOKING 579 | #define HOOKFUNC(R, N, args...) R pxcng_ ## N ( EXPAND(args) ) 580 | #else 581 | #define HOOKFUNC(R, N, args...) R N ( EXPAND(args) ) 582 | #endif 583 | 584 | HOOKFUNC(int, close, int fd) { 585 | if(!init_l) { 586 | if(close_fds_cnt>=(sizeof close_fds/sizeof close_fds[0])) goto err; 587 | close_fds[close_fds_cnt++] = fd; 588 | errno = 0; 589 | return 0; 590 | } 591 | if(proxychains_resolver != DNSLF_RDNS_THREAD) return true_close(fd); 592 | 593 | /* prevent rude programs (like ssh) from closing our pipes */ 594 | if(fd != req_pipefd[0] && fd != req_pipefd[1] && 595 | fd != resp_pipefd[0] && fd != resp_pipefd[1]) { 596 | return true_close(fd); 597 | } 598 | err: 599 | errno = EBADF; 600 | return -1; 601 | } 602 | static int is_v4inv6(const struct in6_addr *a) { 603 | return !memcmp(a->s6_addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); 604 | } 605 | 606 | static void intsort(int *a, int n) { 607 | int i, j, s; 608 | for(i=0; i= (sizeof close_range_buffer / sizeof close_range_buffer[0])) { 626 | errno = ENOMEM; 627 | return -1; 628 | } 629 | int i = close_range_buffer_cnt++; 630 | close_range_buffer[i].first = first; 631 | close_range_buffer[i].last = last; 632 | close_range_buffer[i].flags = flags; 633 | return errno = 0; 634 | } 635 | if(proxychains_resolver != DNSLF_RDNS_THREAD) return true_close_range(first, last, flags); 636 | 637 | /* prevent rude programs (like ssh) from closing our pipes */ 638 | int res = 0, uerrno = 0, i; 639 | int protected_fds[] = {req_pipefd[0], req_pipefd[1], resp_pipefd[0], resp_pipefd[1]}; 640 | intsort(protected_fds, 4); 641 | /* We are skipping protected_fds while calling true_close_range() 642 | * If protected_fds cut the range into some sub-ranges, we close sub-ranges BEFORE cut point in the loop. 643 | * [first, cut1-1] , [cut1+1, cut2-1] , [cut2+1, cut3-1] 644 | * Finally, we delete the remaining sub-range, outside the loop. [cut3+1, tail] 645 | */ 646 | int next_fd_to_close = first; 647 | for(i = 0; i < 4; ++i) { 648 | if(protected_fds[i] < first || protected_fds[i] > last) 649 | continue; 650 | int prev = (i == 0 || protected_fds[i-1] < first) ? first : protected_fds[i-1]+1; 651 | if(prev != protected_fds[i]) { 652 | if(-1 == true_close_range(prev, protected_fds[i]-1, flags)) { 653 | res = -1; 654 | uerrno = errno; 655 | } 656 | } 657 | next_fd_to_close = protected_fds[i]+1; 658 | } 659 | if(next_fd_to_close <= last) { 660 | if(-1 == true_close_range(next_fd_to_close, last, flags)) { 661 | res = -1; 662 | uerrno = errno; 663 | } 664 | } 665 | errno = uerrno; 666 | return res; 667 | } 668 | 669 | HOOKFUNC(int, connect, int sock, const struct sockaddr *addr, unsigned int len) { 670 | INIT(); 671 | PFUNC(); 672 | 673 | int socktype = 0, flags = 0, ret = 0; 674 | socklen_t optlen = 0; 675 | ip_type dest_ip; 676 | DEBUGDECL(char str[256]); 677 | 678 | struct in_addr *p_addr_in; 679 | struct in6_addr *p_addr_in6; 680 | dnat_arg *dnat = NULL; 681 | unsigned short port; 682 | size_t i; 683 | int remote_dns_connect = 0; 684 | optlen = sizeof(socktype); 685 | sa_family_t fam = SOCKFAMILY(*addr); 686 | getsockopt(sock, SOL_SOCKET, SO_TYPE, &socktype, &optlen); 687 | if(!((fam == AF_INET || fam == AF_INET6) && socktype == SOCK_STREAM)) 688 | return true_connect(sock, addr, len); 689 | 690 | int v6 = dest_ip.is_v6 = fam == AF_INET6; 691 | 692 | p_addr_in = &((struct sockaddr_in *) addr)->sin_addr; 693 | p_addr_in6 = &((struct sockaddr_in6 *) addr)->sin6_addr; 694 | port = !v6 ? ntohs(((struct sockaddr_in *) addr)->sin_port) 695 | : ntohs(((struct sockaddr_in6 *) addr)->sin6_port); 696 | struct in_addr v4inv6; 697 | if(v6 && is_v4inv6(p_addr_in6)) { 698 | memcpy(&v4inv6.s_addr, &p_addr_in6->s6_addr[12], 4); 699 | v6 = dest_ip.is_v6 = 0; 700 | p_addr_in = &v4inv6; 701 | } 702 | if(!v6 && !memcmp(p_addr_in, "\0\0\0\0", 4)) { 703 | errno = ECONNREFUSED; 704 | return -1; 705 | } 706 | 707 | // PDEBUG("localnet: %s; ", inet_ntop(AF_INET,&in_addr_localnet, str, sizeof(str))); 708 | // PDEBUG("netmask: %s; " , inet_ntop(AF_INET, &in_addr_netmask, str, sizeof(str))); 709 | PDEBUG("target: %s\n", inet_ntop(v6 ? AF_INET6 : AF_INET, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, str, sizeof(str))); 710 | PDEBUG("port: %d\n", port); 711 | 712 | // check if connect called from proxydns 713 | remote_dns_connect = !v6 && (ntohl(p_addr_in->s_addr) >> 24 == remote_dns_subnet); 714 | 715 | // more specific first 716 | if (!v6) for(i = 0; i < num_dnats && !remote_dns_connect && !dnat; i++) 717 | if(dnats[i].orig_dst.s_addr == p_addr_in->s_addr) 718 | if(dnats[i].orig_port && (dnats[i].orig_port == port)) 719 | dnat = &dnats[i]; 720 | 721 | if (!v6) for(i = 0; i < num_dnats && !remote_dns_connect && !dnat; i++) 722 | if(dnats[i].orig_dst.s_addr == p_addr_in->s_addr) 723 | if(!dnats[i].orig_port) 724 | dnat = &dnats[i]; 725 | 726 | if (dnat) { 727 | p_addr_in = &dnat->new_dst; 728 | if (dnat->new_port) 729 | port = dnat->new_port; 730 | } 731 | 732 | for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) { 733 | if (localnet_addr[i].port && localnet_addr[i].port != port) 734 | continue; 735 | if (localnet_addr[i].family != (v6 ? AF_INET6 : AF_INET)) 736 | continue; 737 | if (v6) { 738 | size_t prefix_bytes = localnet_addr[i].in6_prefix / CHAR_BIT; 739 | size_t prefix_bits = localnet_addr[i].in6_prefix % CHAR_BIT; 740 | if (prefix_bytes && memcmp(p_addr_in6->s6_addr, localnet_addr[i].in6_addr.s6_addr, prefix_bytes) != 0) 741 | continue; 742 | if (prefix_bits && (p_addr_in6->s6_addr[prefix_bytes] ^ localnet_addr[i].in6_addr.s6_addr[prefix_bytes]) >> (CHAR_BIT - prefix_bits)) 743 | continue; 744 | } else { 745 | if((p_addr_in->s_addr ^ localnet_addr[i].in_addr.s_addr) & localnet_addr[i].in_mask.s_addr) 746 | continue; 747 | } 748 | PDEBUG("accessing localnet using true_connect\n"); 749 | return true_connect(sock, addr, len); 750 | } 751 | 752 | flags = fcntl(sock, F_GETFL, 0); 753 | if(flags & O_NONBLOCK) 754 | fcntl(sock, F_SETFL, !O_NONBLOCK); 755 | 756 | memcpy(dest_ip.addr.v6, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, v6?16:4); 757 | 758 | ret = connect_proxy_chain(sock, 759 | dest_ip, 760 | htons(port), 761 | proxychains_pd, proxychains_proxy_count, proxychains_ct, proxychains_max_chain); 762 | 763 | fcntl(sock, F_SETFL, flags); 764 | if(ret != SUCCESS) 765 | errno = ECONNREFUSED; 766 | return ret; 767 | } 768 | 769 | #ifdef IS_SOLARIS 770 | HOOKFUNC(int, __xnet_connect, int sock, const struct sockaddr *addr, unsigned int len) { 771 | return connect(sock, addr, len); 772 | } 773 | #endif 774 | 775 | static struct gethostbyname_data ghbndata; 776 | HOOKFUNC(struct hostent*, gethostbyname, const char *name) { 777 | INIT(); 778 | PDEBUG("gethostbyname: %s\n", name); 779 | 780 | if(proxychains_resolver == DNSLF_FORKEXEC) 781 | return proxy_gethostbyname_old(name); 782 | else if(proxychains_resolver == DNSLF_LIBC) 783 | return true_gethostbyname(name); 784 | else 785 | return proxy_gethostbyname(name, &ghbndata); 786 | 787 | return NULL; 788 | } 789 | 790 | HOOKFUNC(int, getaddrinfo, const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { 791 | INIT(); 792 | PDEBUG("getaddrinfo: %s %s\n", node ? node : "null", service ? service : "null"); 793 | 794 | if(proxychains_resolver != DNSLF_LIBC) 795 | return proxy_getaddrinfo(node, service, hints, res); 796 | else 797 | return true_getaddrinfo(node, service, hints, res); 798 | } 799 | 800 | HOOKFUNC(void, freeaddrinfo, struct addrinfo *res) { 801 | INIT(); 802 | PDEBUG("freeaddrinfo %p \n", (void *) res); 803 | 804 | if(proxychains_resolver == DNSLF_LIBC) 805 | true_freeaddrinfo(res); 806 | else 807 | proxy_freeaddrinfo(res); 808 | } 809 | 810 | HOOKFUNC(int, getnameinfo, const struct sockaddr *sa, socklen_t salen, 811 | char *host, GN_NODELEN_T hostlen, char *serv, 812 | GN_SERVLEN_T servlen, GN_FLAGS_T flags) 813 | { 814 | INIT(); 815 | PFUNC(); 816 | 817 | if(proxychains_resolver == DNSLF_LIBC) { 818 | return true_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); 819 | } else { 820 | if(!salen || !(SOCKFAMILY(*sa) == AF_INET || SOCKFAMILY(*sa) == AF_INET6)) 821 | return EAI_FAMILY; 822 | int v6 = SOCKFAMILY(*sa) == AF_INET6; 823 | if(salen < (v6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in))) 824 | return EAI_FAMILY; 825 | if(hostlen) { 826 | unsigned char v4inv6buf[4]; 827 | const void *ip = v6 ? (void*)&((struct sockaddr_in6*)sa)->sin6_addr 828 | : (void*)&((struct sockaddr_in*)sa)->sin_addr; 829 | unsigned scopeid = 0; 830 | if(v6) { 831 | if(is_v4inv6(&((struct sockaddr_in6*)sa)->sin6_addr)) { 832 | memcpy(v4inv6buf, &((struct sockaddr_in6*)sa)->sin6_addr.s6_addr[12], 4); 833 | ip = v4inv6buf; 834 | v6 = 0; 835 | } else 836 | scopeid = ((struct sockaddr_in6 *)sa)->sin6_scope_id; 837 | } 838 | if(!inet_ntop(v6?AF_INET6:AF_INET,ip,host,hostlen)) 839 | return EAI_OVERFLOW; 840 | if(scopeid) { 841 | size_t l = strlen(host); 842 | if(snprintf(host+l, hostlen-l, "%%%u", scopeid) >= hostlen-l) 843 | return EAI_OVERFLOW; 844 | } 845 | } 846 | if(servlen) { 847 | if(snprintf(serv, servlen, "%d", ntohs(SOCKPORT(*sa))) >= servlen) 848 | return EAI_OVERFLOW; 849 | } 850 | } 851 | return 0; 852 | } 853 | 854 | HOOKFUNC(struct hostent*, gethostbyaddr, const void *addr, socklen_t len, int type) { 855 | INIT(); 856 | PDEBUG("TODO: proper gethostbyaddr hook\n"); 857 | 858 | static char buf[16]; 859 | static char ipv4[4]; 860 | static char *list[2]; 861 | static char *aliases[1]; 862 | static struct hostent he; 863 | 864 | if(proxychains_resolver == DNSLF_LIBC) 865 | return true_gethostbyaddr(addr, len, type); 866 | else { 867 | 868 | PDEBUG("len %u\n", len); 869 | if(len != 4) 870 | return NULL; 871 | he.h_name = buf; 872 | memcpy(ipv4, addr, 4); 873 | list[0] = ipv4; 874 | list[1] = NULL; 875 | he.h_addr_list = list; 876 | he.h_addrtype = AF_INET; 877 | aliases[0] = NULL; 878 | he.h_aliases = aliases; 879 | he.h_length = 4; 880 | pc_stringfromipv4((unsigned char *) addr, buf); 881 | return &he; 882 | } 883 | return NULL; 884 | } 885 | 886 | #ifndef MSG_FASTOPEN 887 | # define MSG_FASTOPEN 0x20000000 888 | #endif 889 | 890 | HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, 891 | const struct sockaddr *dest_addr, socklen_t addrlen) { 892 | INIT(); 893 | PFUNC(); 894 | if (flags & MSG_FASTOPEN) { 895 | if (!connect(sockfd, dest_addr, addrlen) && errno != EINPROGRESS) { 896 | return -1; 897 | } 898 | dest_addr = NULL; 899 | addrlen = 0; 900 | flags &= ~MSG_FASTOPEN; 901 | } 902 | return true_sendto(sockfd, buf, len, flags, dest_addr, addrlen); 903 | } 904 | 905 | #ifdef MONTEREY_HOOKING 906 | #define SETUP_SYM(X) do { if (! true_ ## X ) true_ ## X = &X; } while(0) 907 | #define SETUP_SYM_OPTIONAL(X) 908 | #else 909 | #define SETUP_SYM_IMPL(X, IS_MANDATORY) do { if (! true_ ## X ) true_ ## X = load_sym( # X, X, IS_MANDATORY ); } while(0) 910 | #define SETUP_SYM(X) SETUP_SYM_IMPL(X, 1) 911 | #define SETUP_SYM_OPTIONAL(X) SETUP_SYM_IMPL(X, 0) 912 | #endif 913 | 914 | static void setup_hooks(void) { 915 | SETUP_SYM(connect); 916 | SETUP_SYM(sendto); 917 | SETUP_SYM(gethostbyname); 918 | SETUP_SYM(getaddrinfo); 919 | SETUP_SYM(freeaddrinfo); 920 | SETUP_SYM(gethostbyaddr); 921 | SETUP_SYM(getnameinfo); 922 | #ifdef IS_SOLARIS 923 | SETUP_SYM(__xnet_connect); 924 | #endif 925 | SETUP_SYM(close); 926 | SETUP_SYM_OPTIONAL(close_range); 927 | } 928 | 929 | #ifdef MONTEREY_HOOKING 930 | 931 | #define DYLD_INTERPOSE(_replacement,_replacee) \ 932 | __attribute__((used)) static struct{ const void* replacement; const void* replacee; } _interpose_##_replacee \ 933 | __attribute__((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacement, (const void*)(unsigned long)&_replacee }; 934 | #define DYLD_HOOK(F) DYLD_INTERPOSE(pxcng_ ## F, F) 935 | 936 | DYLD_HOOK(connect); 937 | DYLD_HOOK(sendto); 938 | DYLD_HOOK(gethostbyname); 939 | DYLD_HOOK(getaddrinfo); 940 | DYLD_HOOK(freeaddrinfo); 941 | DYLD_HOOK(gethostbyaddr); 942 | DYLD_HOOK(getnameinfo); 943 | DYLD_HOOK(close); 944 | 945 | #endif 946 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* (C) 2011, 2012 rofl0r 2 | * * 3 | * This program is free software; you can redistribute it and/or modify * 4 | * it under the terms of the GNU General Public License as published by * 5 | * the Free Software Foundation; either version 2 of the License, or * 6 | * (at your option) any later version. * 7 | * * 8 | ***************************************************************************/ 9 | 10 | #define _DEFAULT_SOURCE 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #ifdef IS_MAC 20 | #define _DARWIN_C_SOURCE 21 | #endif 22 | #include 23 | 24 | #include "common.h" 25 | 26 | static int usage(char **argv) { 27 | printf("\nUsage:\t%s -q -f config_file program_name [arguments]\n" 28 | "\t-q makes proxychains quiet - this overrides the config setting\n" 29 | "\t-f allows one to manually specify a configfile to use\n" 30 | "\tfor example : proxychains telnet somehost.com\n" "More help in README file\n\n", argv[0]); 31 | return EXIT_FAILURE; 32 | } 33 | 34 | static const char *dll_name = DLL_NAME; 35 | 36 | static char own_dir[256]; 37 | static const char *dll_dirs[] = { 38 | #ifndef SUPER_SECURE /* CVE-2015-3887 */ 39 | ".", 40 | #endif 41 | own_dir, 42 | LIB_DIR, 43 | "/lib", 44 | "/usr/lib", 45 | "/usr/local/lib", 46 | "/lib64", 47 | NULL 48 | }; 49 | 50 | static void set_own_dir(const char *argv0) { 51 | size_t l = strlen(argv0); 52 | while(l && argv0[l - 1] != '/') 53 | l--; 54 | if(l == 0 || l >= sizeof(own_dir)) 55 | #ifdef SUPER_SECURE 56 | memcpy(own_dir, "/dev/null/", 11); 57 | #else 58 | memcpy(own_dir, ".", 2); 59 | #endif 60 | else { 61 | memcpy(own_dir, argv0, l - 1); 62 | own_dir[l] = 0; 63 | } 64 | } 65 | 66 | #define MAX_COMMANDLINE_FLAGS 2 67 | 68 | int main(int argc, char *argv[]) { 69 | char *path = NULL; 70 | char buf[256]; 71 | char pbuf[256]; 72 | int start_argv = 1; 73 | int quiet = 0; 74 | size_t i; 75 | const char *prefix = NULL; 76 | 77 | if(argc == 2 && !strcmp(argv[1], "--help")) 78 | return usage(argv); 79 | 80 | for(i = 0; i < MAX_COMMANDLINE_FLAGS; i++) { 81 | if(start_argv < argc && argv[start_argv][0] == '-') { 82 | if(argv[start_argv][1] == 'q') { 83 | quiet = 1; 84 | start_argv++; 85 | } else if(argv[start_argv][1] == 'f') { 86 | 87 | if(start_argv + 1 < argc) 88 | path = argv[start_argv + 1]; 89 | else 90 | return usage(argv); 91 | 92 | start_argv += 2; 93 | } 94 | } else 95 | break; 96 | } 97 | 98 | if(start_argv >= argc) 99 | return usage(argv); 100 | 101 | /* check if path of config file has not been passed via command line */ 102 | path = get_config_path(path, pbuf, sizeof(pbuf)); 103 | 104 | if(!quiet) 105 | fprintf(stderr, LOG_PREFIX "config file found: %s\n", path); 106 | 107 | /* Set PROXYCHAINS_CONF_FILE to get proxychains lib to use new config file. */ 108 | setenv(PROXYCHAINS_CONF_FILE_ENV_VAR, path, 1); 109 | 110 | if(quiet) 111 | setenv(PROXYCHAINS_QUIET_MODE_ENV_VAR, "1", 1); 112 | 113 | 114 | // search DLL 115 | 116 | Dl_info dli; 117 | dladdr(own_dir, &dli); 118 | set_own_dir(dli.dli_fname); 119 | 120 | i = 0; 121 | 122 | while(dll_dirs[i]) { 123 | snprintf(buf, sizeof(buf), "%s/%s", dll_dirs[i], dll_name); 124 | if(access(buf, R_OK) != -1) { 125 | prefix = dll_dirs[i]; 126 | break; 127 | } 128 | i++; 129 | } 130 | 131 | if(!prefix) { 132 | fprintf(stderr, "couldnt locate %s\n", dll_name); 133 | return EXIT_FAILURE; 134 | } 135 | if(!quiet) 136 | fprintf(stderr, LOG_PREFIX "preloading %s/%s\n", prefix, dll_name); 137 | 138 | #if defined(IS_MAC) || defined(IS_OPENBSD) 139 | #define LD_PRELOAD_SEP ":" 140 | #else 141 | /* Dynlinkers for Linux and most BSDs seem to support space 142 | as LD_PRELOAD separator, with colon added only recently. 143 | We use the old syntax for maximum compat */ 144 | #define LD_PRELOAD_SEP " " 145 | #endif 146 | 147 | #ifdef IS_MAC 148 | putenv("DYLD_FORCE_FLAT_NAMESPACE=1"); 149 | #define LD_PRELOAD_ENV "DYLD_INSERT_LIBRARIES" 150 | #else 151 | #define LD_PRELOAD_ENV "LD_PRELOAD" 152 | #endif 153 | char *old_val = getenv(LD_PRELOAD_ENV); 154 | snprintf(buf, sizeof(buf), LD_PRELOAD_ENV "=%s/%s%s%s", 155 | prefix, dll_name, 156 | /* append previous LD_PRELOAD content, if existent */ 157 | old_val ? LD_PRELOAD_SEP : "", 158 | old_val ? old_val : ""); 159 | putenv(buf); 160 | execvp(argv[start_argv], &argv[start_argv]); 161 | fprintf(stderr, "proxychains: can't load process '%s'.", argv[start_argv]); 162 | perror(" (hint: it's probably a typo)"); 163 | 164 | return EXIT_FAILURE; 165 | } 166 | -------------------------------------------------------------------------------- /src/mutex.h: -------------------------------------------------------------------------------- 1 | #ifndef MUTEX_H 2 | #define MUTEX_H 3 | 4 | #include 5 | # define MUTEX_LOCK(x) pthread_mutex_lock(x) 6 | # define MUTEX_UNLOCK(x) pthread_mutex_unlock(x) 7 | # define MUTEX_INIT(x) pthread_mutex_init(x, NULL) 8 | # define MUTEX_DESTROY(x) pthread_mutex_destroy(x) 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/proxychains.conf: -------------------------------------------------------------------------------- 1 | # proxychains.conf VER 4.x 2 | # 3 | # HTTP, SOCKS4a, SOCKS5 tunneling proxifier with DNS. 4 | 5 | 6 | # The option below identifies how the ProxyList is treated. 7 | # only one option should be uncommented at time, 8 | # otherwise the last appearing option will be accepted 9 | # 10 | #dynamic_chain 11 | # 12 | # Dynamic - Each connection will be done via chained proxies 13 | # all proxies chained in the order as they appear in the list 14 | # at least one proxy must be online to play in chain 15 | # (dead proxies are skipped) 16 | # otherwise EINTR is returned to the app 17 | # 18 | strict_chain 19 | # 20 | # Strict - Each connection will be done via chained proxies 21 | # all proxies chained in the order as they appear in the list 22 | # all proxies must be online to play in chain 23 | # otherwise EINTR is returned to the app 24 | # 25 | #round_robin_chain 26 | # 27 | # Round Robin - Each connection will be done via chained proxies 28 | # of chain_len length 29 | # all proxies chained in the order as they appear in the list 30 | # at least one proxy must be online to play in chain 31 | # (dead proxies are skipped). 32 | # the start of the current proxy chain is the proxy after the last 33 | # proxy in the previously invoked proxy chain. 34 | # if the end of the proxy chain is reached while looking for proxies 35 | # start at the beginning again. 36 | # otherwise EINTR is returned to the app 37 | # These semantics are not guaranteed in a multithreaded environment. 38 | # 39 | #random_chain 40 | # 41 | # Random - Each connection will be done via random proxy 42 | # (or proxy chain, see chain_len) from the list. 43 | # this option is good to test your IDS :) 44 | 45 | # Make sense only if random_chain or round_robin_chain 46 | #chain_len = 2 47 | 48 | # Quiet mode (no output from library) 49 | #quiet_mode 50 | 51 | ## Proxy DNS requests - no leak for DNS data 52 | # (disable all of the 3 items below to not proxy your DNS requests) 53 | 54 | # method 1. this uses the proxychains4 style method to do remote dns: 55 | # a thread is spawned that serves DNS requests and hands down an ip 56 | # assigned from an internal list (via remote_dns_subnet). 57 | # this is the easiest (setup-wise) and fastest method, however on 58 | # systems with buggy libcs and very complex software like webbrowsers 59 | # this might not work and/or cause crashes. 60 | proxy_dns 61 | 62 | # method 2. use the old proxyresolv script to proxy DNS requests 63 | # in proxychains 3.1 style. requires `proxyresolv` in $PATH 64 | # plus a dynamically linked `dig` binary. 65 | # this is a lot slower than `proxy_dns`, doesn't support .onion URLs, 66 | # but might be more compatible with complex software like webbrowsers. 67 | #proxy_dns_old 68 | 69 | # method 3. use proxychains4-daemon process to serve remote DNS requests. 70 | # this is similar to the threaded `proxy_dns` method, however it requires 71 | # that proxychains4-daemon is already running on the specified address. 72 | # on the plus side it doesn't do malloc/threads so it should be quite 73 | # compatible with complex, async-unsafe software. 74 | # note that if you don't start proxychains4-daemon before using this, 75 | # the process will simply hang. 76 | #proxy_dns_daemon 127.0.0.1:1053 77 | 78 | # set the class A subnet number to use for the internal remote DNS mapping 79 | # we use the reserved 224.x.x.x range by default, 80 | # if the proxified app does a DNS request, we will return an IP from that range. 81 | # on further accesses to this ip we will send the saved DNS name to the proxy. 82 | # in case some control-freak app checks the returned ip, and denies to 83 | # connect, you can use another subnet, e.g. 10.x.x.x or 127.x.x.x. 84 | # of course you should make sure that the proxified app does not need 85 | # *real* access to this subnet. 86 | # i.e. dont use the same subnet then in the localnet section 87 | #remote_dns_subnet 127 88 | #remote_dns_subnet 10 89 | remote_dns_subnet 224 90 | 91 | # Some timeouts in milliseconds 92 | tcp_read_time_out 15000 93 | tcp_connect_time_out 8000 94 | 95 | ### Examples for localnet exclusion 96 | ## localnet ranges will *not* use a proxy to connect. 97 | ## note that localnet works only when plain IP addresses are passed to the app, 98 | ## the hostname resolves via /etc/hosts, or proxy_dns is disabled or proxy_dns_old used. 99 | 100 | ## Exclude connections to 192.168.1.0/24 with port 80 101 | # localnet 192.168.1.0:80/255.255.255.0 102 | 103 | ## Exclude connections to 192.168.100.0/24 104 | # localnet 192.168.100.0/255.255.255.0 105 | 106 | ## Exclude connections to ANYwhere with port 80 107 | # localnet 0.0.0.0:80/0.0.0.0 108 | # localnet [::]:80/0 109 | 110 | ## RFC6890 Loopback address range 111 | ## if you enable this, you have to make sure remote_dns_subnet is not 127 112 | ## you'll need to enable it if you want to use an application that 113 | ## connects to localhost. 114 | # localnet 127.0.0.0/255.0.0.0 115 | # localnet ::1/128 116 | 117 | ## RFC1918 Private Address Ranges 118 | # localnet 10.0.0.0/255.0.0.0 119 | # localnet 172.16.0.0/255.240.0.0 120 | # localnet 192.168.0.0/255.255.0.0 121 | 122 | ### Examples for dnat 123 | ## Trying to proxy connections to destinations which are dnatted, 124 | ## will result in proxying connections to the new given destinations. 125 | ## Whenever I connect to 1.1.1.1 on port 1234 actually connect to 1.1.1.2 on port 443 126 | # dnat 1.1.1.1:1234 1.1.1.2:443 127 | 128 | ## Whenever I connect to 1.1.1.1 on port 443 actually connect to 1.1.1.2 on port 443 129 | ## (no need to write :443 again) 130 | # dnat 1.1.1.2:443 1.1.1.2 131 | 132 | ## No matter what port I connect to on 1.1.1.1 port actually connect to 1.1.1.2 on port 443 133 | # dnat 1.1.1.1 1.1.1.2:443 134 | 135 | ## Always, instead of connecting to 1.1.1.1, connect to 1.1.1.2 136 | # dnat 1.1.1.1 1.1.1.2 137 | 138 | # ProxyList format 139 | # type ip port [user pass] 140 | # (values separated by 'tab' or 'blank') 141 | # 142 | # only numeric ipv4 addresses are valid 143 | # 144 | # 145 | # Examples: 146 | # 147 | # socks5 192.168.67.78 1080 lamer secret 148 | # http 192.168.89.3 8080 justu hidden 149 | # socks4 192.168.1.49 1080 150 | # http 192.168.39.93 8080 151 | # 152 | # 153 | # proxy types: http, socks4, socks5, raw 154 | # * raw: The traffic is simply forwarded to the proxy without modification. 155 | # ( auth types supported: "basic"-http "user/pass"-socks ) 156 | # 157 | [ProxyList] 158 | # add proxy here ... 159 | # meanwile 160 | # defaults set to "tor" 161 | socks4 127.0.0.1 9050 162 | 163 | -------------------------------------------------------------------------------- /src/proxyresolv: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This is a legacy script that uses "dig" or "drill" to do DNS lookups via TCP. 3 | 4 | # DNS server used to resolve names 5 | test -z "$DNS_SERVER" && DNS_SERVER=8.8.8.8 6 | 7 | 8 | if [ $# = 0 ] ; then 9 | echo " usage:" 10 | echo " proxyresolv " 11 | exit 12 | fi 13 | 14 | 15 | test -z $LD_PRELOAD && export LD_PRELOAD=libproxychains4.so 16 | 17 | if type dig 1>/dev/null 2>&1 ; then 18 | dig $1 @$DNS_SERVER +tcp | awk '/A.?[0-9]+\.[0-9]+\.[0-9]/{print $5;}' 19 | elif type drill 1>/dev/null 2>&1 ; then 20 | drill -t4 $1 @$DNS_SERVER | awk '/A.+[0-9]+\.[0-9]+\.[0-9]/{print $5;}' 21 | else 22 | echo "error: neither dig nor drill found" >&2 23 | fi 24 | -------------------------------------------------------------------------------- /src/rdns.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "rdns.h" 6 | #include "allocator_thread.h" 7 | #include "remotedns.h" 8 | 9 | #ifndef HAVE_SOCK_CLOEXEC 10 | #define SOCK_CLOEXEC 0 11 | #endif 12 | 13 | //static enum dns_lookup_flavor dns_flavor; 14 | #define dns_flavor rdns_get_flavor() 15 | 16 | static struct sockaddr_in rdns_server; 17 | 18 | size_t rdns_daemon_get_host_for_ip(ip_type4 ip, char* readbuf) { 19 | struct at_msg msg = { 20 | .h.msgtype = ATM_GETNAME, 21 | .h.datalen = htons(4), 22 | .m.ip = ip, 23 | }; 24 | int fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0); 25 | sendto(fd, &msg, sizeof(msg.h)+4, 0, (void*)&rdns_server, sizeof(rdns_server)); 26 | recvfrom(fd, &msg, sizeof msg, 0, (void*)0, (void*)0); 27 | close(fd); 28 | msg.h.datalen = ntohs(msg.h.datalen); 29 | if(!msg.h.datalen || msg.h.datalen > 256) return 0; 30 | memcpy(readbuf, msg.m.host, msg.h.datalen); 31 | return msg.h.datalen - 1; 32 | } 33 | 34 | static ip_type4 rdns_daemon_get_ip_for_host(char* host, size_t len) { 35 | struct at_msg msg = { 36 | .h.msgtype = ATM_GETIP, 37 | }; 38 | if(len >= 256) return IPT4_INT(-1); 39 | memcpy(msg.m.host, host, len+1); 40 | msg.h.datalen = htons(len+1); 41 | int fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0); 42 | sendto(fd, &msg, sizeof(msg.h)+len+1, 0, (void*)&rdns_server, sizeof(rdns_server)); 43 | recvfrom(fd, &msg, sizeof msg, 0, (void*)0, (void*)0); 44 | close(fd); 45 | if(ntohs(msg.h.datalen) != 4) return IPT4_INT(-1); 46 | return msg.m.ip; 47 | } 48 | 49 | const char *rdns_resolver_string(enum dns_lookup_flavor flavor) { 50 | static const char tab[][7] = { 51 | [DNSLF_LIBC] = "off", 52 | [DNSLF_FORKEXEC] = "old", 53 | [DNSLF_RDNS_THREAD] = "thread", 54 | [DNSLF_RDNS_DAEMON] = "daemon", 55 | }; 56 | return tab[flavor]; 57 | } 58 | 59 | void rdns_init(enum dns_lookup_flavor flavor) { 60 | static int init_done = 0; 61 | if(!init_done) switch(flavor) { 62 | case DNSLF_RDNS_THREAD: 63 | at_init(); 64 | break; 65 | case DNSLF_RDNS_DAEMON: 66 | default: 67 | break; 68 | } 69 | init_done = 1; 70 | } 71 | 72 | void rdns_set_daemon(struct sockaddr_in* addr) { 73 | rdns_server = *addr; 74 | } 75 | 76 | #if 0 77 | enum dns_lookup_flavor rdns_get_flavor(void) { 78 | return dns_flavor; 79 | } 80 | #endif 81 | 82 | size_t rdns_get_host_for_ip(ip_type4 ip, char* readbuf) { 83 | switch(dns_flavor) { 84 | case DNSLF_RDNS_THREAD: return at_get_host_for_ip(ip, readbuf); 85 | case DNSLF_RDNS_DAEMON: return rdns_daemon_get_host_for_ip(ip, readbuf); 86 | default: 87 | abort(); 88 | } 89 | } 90 | 91 | ip_type4 rdns_get_ip_for_host(char* host, size_t len) { 92 | switch(dns_flavor) { 93 | case DNSLF_RDNS_THREAD: return at_get_ip_for_host(host, len); 94 | case DNSLF_RDNS_DAEMON: return rdns_daemon_get_ip_for_host(host, len); 95 | default: 96 | abort(); 97 | } 98 | } 99 | 100 | -------------------------------------------------------------------------------- /src/rdns.h: -------------------------------------------------------------------------------- 1 | #ifndef RDNS_H 2 | #define RDNS_H 3 | 4 | #include 5 | #include 6 | #include "ip_type.h" 7 | #include "remotedns.h" 8 | 9 | enum dns_lookup_flavor { 10 | DNSLF_LIBC = 0, 11 | DNSLF_FORKEXEC, 12 | 13 | DNSLF_RDNS_START, 14 | DNSLF_RDNS_THREAD = DNSLF_RDNS_START, 15 | DNSLF_RDNS_DAEMON, 16 | }; 17 | 18 | void rdns_init(enum dns_lookup_flavor flavor); 19 | void rdns_set_daemon(struct sockaddr_in* addr); 20 | const char *rdns_resolver_string(enum dns_lookup_flavor flavor); 21 | size_t rdns_get_host_for_ip(ip_type4 ip, char* readbuf); 22 | ip_type4 rdns_get_ip_for_host(char* host, size_t len); 23 | 24 | //enum dns_lookup_flavor rdns_get_flavor(void); 25 | #define rdns_get_flavor() proxychains_resolver 26 | extern enum dns_lookup_flavor proxychains_resolver; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/remotedns.h: -------------------------------------------------------------------------------- 1 | #ifndef REMOTEDNS_H 2 | #define REMOTEDNS_H 3 | 4 | #include 5 | #include "ip_type.h" 6 | 7 | #define MSG_LEN_MAX 256 8 | 9 | enum at_msgtype { 10 | ATM_GETIP = 0, 11 | ATM_GETNAME, 12 | ATM_FAIL, 13 | ATM_EXIT, 14 | }; 15 | 16 | struct at_msghdr { 17 | unsigned char msgtype; /* at_msgtype */ 18 | char reserved; 19 | unsigned short datalen; 20 | }; 21 | 22 | struct at_msg { 23 | struct at_msghdr h; 24 | union { 25 | char host[260]; 26 | ip_type4 ip; 27 | } m; 28 | }; 29 | 30 | #endif 31 | 32 | -------------------------------------------------------------------------------- /src/version.c: -------------------------------------------------------------------------------- 1 | #include "version.h" 2 | static const char version[] = VERSION; 3 | const char *proxychains_get_version(void) { 4 | return version; 5 | } 6 | 7 | -------------------------------------------------------------------------------- /tests/test_getaddrinfo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifndef NI_MAXHOST 10 | #define NI_MAXHOST 1025 11 | #endif 12 | 13 | static int doit(const char* host, const char* service) { 14 | struct addrinfo *result; 15 | struct addrinfo *res; 16 | int error; 17 | 18 | /* resolve the domain name into a list of addresses */ 19 | error = getaddrinfo(host, service, NULL, &result); 20 | if (error != 0) 21 | { 22 | fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error)); 23 | return EXIT_FAILURE; 24 | } 25 | 26 | /* loop over all returned results and do inverse lookup */ 27 | for (res = result; res != NULL; res = res->ai_next) 28 | { 29 | char hostname[NI_MAXHOST] = ""; 30 | 31 | error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0); 32 | if (error != 0) 33 | { 34 | fprintf(stderr, "error in getnameinfo: %s\n", gai_strerror(error)); 35 | continue; 36 | } 37 | int port = 0; 38 | if(res->ai_family == AF_INET) port = ((struct sockaddr_in*)res->ai_addr)->sin_port; 39 | else if(res->ai_family == AF_INET6) port = ((struct sockaddr_in6*)res->ai_addr)->sin6_port; 40 | port = ntohs(port); 41 | printf("hostname: %s, port: %d\n", hostname, port); 42 | } 43 | 44 | freeaddrinfo(result); 45 | return EXIT_SUCCESS; 46 | } 47 | 48 | /* reproduce use of getaddrinfo as used by nmap 7.91's canonicalize_address */ 49 | int canonicalize_address(struct sockaddr_storage *ss, struct sockaddr_storage *output) { 50 | char canonical_ip_string[NI_MAXHOST]; 51 | struct addrinfo *ai; 52 | int rc; 53 | /* Convert address to string. */ 54 | rc = getnameinfo((struct sockaddr *) ss, sizeof(*ss), 55 | canonical_ip_string, sizeof(canonical_ip_string), NULL, 0, NI_NUMERICHOST); 56 | assert(rc == 0); 57 | struct addrinfo hints = { 58 | .ai_family = ss->ss_family, 59 | .ai_socktype = SOCK_DGRAM, 60 | .ai_flags = AI_NUMERICHOST, 61 | }; 62 | rc = getaddrinfo(canonical_ip_string, NULL, &hints, &ai); 63 | if (rc != 0 || ai == NULL) 64 | return -1; 65 | assert(ai->ai_addrlen > 0 && ai->ai_addrlen <= (int) sizeof(*output)); 66 | memcpy(output, ai->ai_addr, ai->ai_addrlen); 67 | freeaddrinfo(ai); 68 | return 0; 69 | } 70 | 71 | int main(void) { 72 | int ret; 73 | ret = doit("www.example.com", NULL); 74 | ret = doit("www.example.com", "80"); 75 | struct sockaddr_storage o, ss = {.ss_family = PF_INET}; 76 | struct sockaddr_in *v4 = &ss; 77 | struct sockaddr_in6 *v6 = &ss; 78 | memcpy(&v4->sin_addr, "\x7f\0\0\1", 4); 79 | ret = canonicalize_address(&ss, &o); 80 | assert (ret == 0); 81 | ss.ss_family = PF_INET6; 82 | memcpy(&v6->sin6_addr, "\0\0\0\0" "\0\0\0\0" "\0\0\0\0""\0\0\0\1", 16); 83 | ret = canonicalize_address(&ss, &o); 84 | assert (ret == 0); 85 | return ret; 86 | } 87 | -------------------------------------------------------------------------------- /tests/test_gethostbyname.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../src/common.c" 4 | 5 | void printhostent(struct hostent *hp) { 6 | char ipbuf[16]; 7 | pc_stringfromipv4(hp->h_addr_list[0], ipbuf); 8 | printf("alias: %p, len: %d, name: %s, addrlist: %p, addrtype: %d, ip: %s\n", 9 | hp->h_aliases, 10 | hp->h_length, 11 | hp->h_name, 12 | hp->h_addr_list, 13 | hp->h_addrtype, 14 | ipbuf 15 | ); 16 | } 17 | int main(int argc, char**argv) { 18 | struct hostent* ret; 19 | if(argc == 1) return 1; 20 | ret = gethostbyname(argv[1]); 21 | if(ret) printhostent(ret); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /tests/test_gethostent.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../src/common.c" 4 | 5 | void printhostent(struct hostent *hp) { 6 | char ipbuf[16]; 7 | pc_stringfromipv4(hp->h_addr_list[0], ipbuf); 8 | printf("alias: %p, len: %d, name: %s, addrlist: %p, addrtype: %d, ip: %s\n", 9 | hp->h_aliases, 10 | hp->h_length, 11 | hp->h_name, 12 | hp->h_addr_list, 13 | hp->h_addrtype, 14 | ipbuf 15 | ); 16 | } 17 | 18 | int main(int argc, char** argv) { 19 | struct hostent *hp; 20 | while((hp = gethostent())) { 21 | printhostent(hp); 22 | } 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /tests/test_gethostent_r.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../src/common.h" 5 | 6 | /* 7 | int gethostent_r( 8 | struct hostent *ret, char *buf, size_t buflen, 9 | struct hostent **result, int *h_errnop); 10 | 11 | Glibc2 also has reentrant versions gethostent_r(), gethostbyaddr_r(), 12 | gethostbyname_r() and gethostbyname2_r(). 13 | 14 | The caller supplies a hostent structure ret which will be filled in on success, 15 | and a temporary work buffer buf of size buflen. 16 | After the call, result will point to the result on success. 17 | In case of an error or if no entry is found result will be NULL. 18 | The functions return 0 on success and a nonzero error number on failure. 19 | In addition to the errors returned by the nonreentrant versions of these functions, 20 | if buf is too small, the functions will return ERANGE, and the call should be retried 21 | with a larger buffer. 22 | The global variable h_errno is not modified, but the address of a variable in which 23 | to store error numbers is passed in h_errnop. 24 | */ 25 | 26 | void printhostent(struct hostent *hp) { 27 | char ipbuf[16]; 28 | pc_stringfromipv4(hp->h_addr_list[0], ipbuf); 29 | printf("alias: %p, len: %d, name: %s, addrlist: %p, addrtype: %d, ip: %s\n", 30 | hp->h_aliases, 31 | hp->h_length, 32 | hp->h_name, 33 | hp->h_addr_list, 34 | hp->h_addrtype, 35 | ipbuf 36 | ); 37 | } 38 | 39 | int main(int argc, char** argv) { 40 | struct hostent he_buf; 41 | struct hostent *he_res; 42 | char h_buf[1024]; 43 | int ch_errno; 44 | int ret; 45 | do { 46 | ret = gethostent_r(&he_buf, h_buf, sizeof(h_buf), &he_res, &ch_errno); 47 | printf("ret: %d, h_errno: %d\n", ret, ch_errno); 48 | if(ret != 0) { 49 | errno = ret; 50 | ret = -1; 51 | } 52 | if(ret == -1) { 53 | perror("gethostent_r"); 54 | break; 55 | } 56 | if(he_res) { 57 | printhostent(he_res); 58 | } 59 | } while (he_res); 60 | return 0; 61 | } -------------------------------------------------------------------------------- /tests/test_getnameinfo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define satosin(x) ((struct sockaddr_in *) &(x)) 9 | #define SOCKADDR(x) (satosin(x)->sin_addr.s_addr) 10 | #define SOCKADDR_2(x) (satosin(x)->sin_addr) 11 | #define SOCKPORT(x) (satosin(x)->sin_port) 12 | #define SOCKFAMILY(x) (satosin(x)->sin_family) 13 | 14 | #define ASSERT(X) { if(!(X)) printf("ASSERTION FAILED: %s @%s:%d\n", # X, __FILE__, __LINE__); } 15 | #define CLR() { hbuf[0] = 0; sbuf[0] = 0; } 16 | 17 | int main() { 18 | struct sockaddr_in a = {0}, *sa = &a; 19 | char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; 20 | a.sin_port = htons(80); 21 | memcpy( &a.sin_addr , (char[]) {127,0,0,1}, 4); 22 | 23 | int ret; 24 | 25 | if ((ret = getnameinfo((void*)sa, 0, hbuf, sizeof(hbuf), sbuf, 26 | sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0) 27 | printf("host=%s, serv=%s\n", hbuf, sbuf); 28 | else 29 | printf("%s\n", gai_strerror(ret)); 30 | 31 | ASSERT(ret == EAI_FAMILY); 32 | CLR(); 33 | 34 | if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, sizeof(hbuf), sbuf, 35 | sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0) 36 | printf("host=%s, serv=%s\n", hbuf, sbuf); 37 | else 38 | printf("%s\n", gai_strerror(ret)); 39 | 40 | ASSERT(ret == EAI_FAMILY); 41 | CLR(); 42 | 43 | SOCKFAMILY(a) = AF_INET; 44 | 45 | if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, 1, sbuf, 46 | sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0) 47 | printf("host=%s, serv=%s\n", hbuf, sbuf); 48 | else 49 | printf("%s\n", gai_strerror(ret)); 50 | 51 | ASSERT(ret == EAI_OVERFLOW); 52 | CLR(); 53 | 54 | if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, 0, sbuf, 55 | 1, NI_NUMERICHOST | NI_NUMERICSERV)) == 0) 56 | printf("host=%s, serv=%s\n", hbuf, sbuf); 57 | else 58 | printf("%s\n", gai_strerror(ret)); 59 | 60 | ASSERT(ret == EAI_OVERFLOW); 61 | CLR(); 62 | 63 | if ((ret = getnameinfo((void*)sa, sizeof(a) - 1, hbuf, 0, sbuf, 64 | sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0) 65 | printf("host=%s, serv=%s\n", hbuf, sbuf); 66 | else 67 | printf("%s\n", gai_strerror(ret)); 68 | 69 | ASSERT(ret == EAI_FAMILY); 70 | CLR(); 71 | 72 | if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, 0, sbuf, 73 | sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0) 74 | printf("host=%s, serv=%s\n", hbuf, sbuf); 75 | else 76 | printf("%s\n", gai_strerror(ret)); 77 | 78 | ASSERT(ret == 0 && !strcmp("80", sbuf)); 79 | CLR(); 80 | 81 | if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, sizeof hbuf, sbuf, 82 | 0, NI_NUMERICHOST | NI_NUMERICSERV)) == 0) 83 | printf("host=%s, serv=%s\n", hbuf, sbuf); 84 | else 85 | printf("%s\n", gai_strerror(ret)); 86 | 87 | ASSERT(ret == 0 && !strcmp("127.0.0.1",hbuf)); 88 | CLR(); 89 | 90 | 91 | if ((ret = getnameinfo((void*)sa, sizeof a, hbuf, sizeof(hbuf), sbuf, 92 | sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0) 93 | printf("host=%s, serv=%s\n", hbuf, sbuf); 94 | else 95 | printf("%s\n", gai_strerror(ret)); 96 | 97 | ASSERT(ret == 0 && !strcmp("127.0.0.1",hbuf) && !strcmp("80", sbuf)); 98 | CLR(); 99 | 100 | struct sockaddr_in6 b = {0}, *sb = &b; 101 | b.sin6_port = htons(8080); 102 | b.sin6_family = AF_INET6; 103 | 104 | memcpy(&b.sin6_addr,"\0\0\0\0\0\0\0\0\0\0\xff\xff\xc0\xa8\1\2", 16); 105 | 106 | if ((ret = getnameinfo((void*)sb, sizeof b, hbuf, sizeof(hbuf), sbuf, 107 | sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) == 0) 108 | printf("host=%s, serv=%s\n", hbuf, sbuf); 109 | else 110 | printf("%s\n", gai_strerror(ret)); 111 | 112 | ASSERT(ret == 0 && !strcmp("192.168.1.2",hbuf) && !strcmp("8080", sbuf)); 113 | CLR(); 114 | 115 | b.sin6_scope_id = 3; 116 | memcpy(&b.sin6_addr,"\0\0\xaa\0\0\0\0\0\0\0\0\xff\xc0\xa8\1\2", 16); 117 | 118 | if ((ret = getnameinfo((void*)sb, sizeof b, hbuf, sizeof(hbuf), sbuf, 119 | sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV | NI_NUMERICSCOPE)) == 0) 120 | printf("host=%s, serv=%s\n", hbuf, sbuf); 121 | else 122 | printf("%s\n", gai_strerror(ret)); 123 | 124 | ASSERT(ret == 0); 125 | 126 | b.sin6_port = 0; 127 | b.sin6_scope_id = 0; 128 | memcpy(&b.sin6_addr,"\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\1", 16); 129 | 130 | if ((ret = getnameinfo((void*)sb, sizeof b, hbuf, sizeof(hbuf), NULL, 131 | 0, NI_NUMERICHOST)) == 0) 132 | printf("host=%s\n", hbuf); 133 | else 134 | printf("%s\n", gai_strerror(ret)); 135 | 136 | ASSERT(ret == 0); 137 | 138 | return 0; 139 | } 140 | -------------------------------------------------------------------------------- /tests/test_proxy_gethostbyname.c: -------------------------------------------------------------------------------- 1 | #include "../src/core.h" 2 | #include "../src/common.h" 3 | #include 4 | 5 | void printhostent(struct hostent *hp) { 6 | char ipbuf[16]; 7 | pc_stringfromipv4(hp->h_addr_list[0], ipbuf); 8 | printf("alias: %p, len: %d, name: %s, addrlist: %p, addrtype: %d, ip: %s\n", 9 | hp->h_aliases, 10 | hp->h_length, 11 | hp->h_name, 12 | hp->h_addr_list, 13 | hp->h_addrtype, 14 | ipbuf 15 | ); 16 | } 17 | int main(int argc, char**argv) { 18 | struct hostent* ret; 19 | struct gethostbyname_data data; 20 | if(argc == 1) return 1; 21 | ret = proxy_gethostbyname(argv[1], &data); 22 | if(ret) printhostent(ret); 23 | return 0; 24 | } -------------------------------------------------------------------------------- /tests/test_sendto.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifndef MSG_FASTOPEN 11 | # define MSG_FASTOPEN 0x20000000 12 | #endif 13 | 14 | void error(const char *msg) 15 | { 16 | perror(msg); 17 | exit(1); 18 | } 19 | 20 | int main(int argc, char *argv[]) 21 | { 22 | if (argc < 4) { 23 | printf("Usage: %s host port method(connect or sendto)\n", argv[0]); 24 | return 1; 25 | } 26 | const char *hostname = argv[1]; 27 | const int portno = atoi(argv[2]); 28 | const char *method = argv[3]; 29 | char request[BUFSIZ]; 30 | sprintf(request, "GET / HTTP/1.0\r\nHost: %s\r\n\r\n", hostname); 31 | int sockfd, n; 32 | struct sockaddr_in serv_addr; 33 | struct hostent *server; 34 | 35 | char buffer[BUFSIZ]; 36 | sockfd = socket(AF_INET, SOCK_STREAM, 0); 37 | if (sockfd < 0) error("ERROR opening socket"); 38 | server = gethostbyname(hostname); 39 | if (server == NULL) { 40 | fprintf(stderr, "%s: no such host\n", hostname); 41 | return 1; 42 | } 43 | memset(&serv_addr, 0, sizeof(serv_addr)); 44 | serv_addr.sin_family = AF_INET; 45 | memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length); 46 | serv_addr.sin_port = htons(portno); 47 | if (!strcmp(method, "connect")) { 48 | if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) 49 | error("connect"); 50 | n = send(sockfd, request, strlen(request), 0); 51 | } else if (!strcmp(method, "sendto")) { 52 | n = sendto(sockfd, request, strlen(request), MSG_FASTOPEN, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); 53 | } else { 54 | printf("Unknown method %s\n", method); 55 | return 1; 56 | } 57 | if (n < 0) 58 | error("send"); 59 | memset(buffer, 0, BUFSIZ); 60 | n = read(sockfd, buffer, BUFSIZ - 1); 61 | if (n < 0) 62 | error("ERROR reading from socket"); 63 | printf("%s\n", buffer); 64 | close(sockfd); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /tests/test_shm.c: -------------------------------------------------------------------------------- 1 | #include "../src/shm.h" 2 | #include 3 | 4 | #define s(A) (sizeof(A) - 1) 5 | #define ss(A) (A), s(A) 6 | 7 | int main() { 8 | char buf4096[4096]; 9 | struct stringpool sp; 10 | stringpool_init(&sp); 11 | char *r; 12 | size_t pos = 0; 13 | r = stringpool_add(&sp, ss("AAAAA")); 14 | assert(r == sp.start); 15 | 16 | pos += s("AAAAA"); 17 | assert(sp.alloced == 4096); 18 | assert(sp.used == pos); 19 | 20 | r = stringpool_add(&sp, buf4096, sizeof(buf4096)); 21 | assert(r == sp.start + pos); 22 | 23 | pos += sizeof(buf4096); 24 | assert(sp.alloced == 4096 * 2); 25 | assert(sp.used == pos); 26 | 27 | r = stringpool_add(&sp, buf4096, 4096 - s("AAAAA")); 28 | assert(r == sp.start + pos); 29 | pos += 4096 - s("AAAAA"); 30 | assert(pos == 4096 * 2); 31 | 32 | assert(sp.alloced == 4096 * 2); 33 | assert(sp.used == pos); 34 | 35 | 36 | 37 | return 0; 38 | 39 | } -------------------------------------------------------------------------------- /tests/test_v4_in_v6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static void v4_to_v6(const struct in_addr *v4, struct in6_addr *v6) { 9 | memset(v6, 0, sizeof(*v6)); 10 | v6->s6_addr[10]=0xff; 11 | v6->s6_addr[11]=0xff; 12 | memcpy(&v6->s6_addr[12], &v4->s_addr, 4); 13 | } 14 | 15 | int main(void) { 16 | struct addrinfo *result; 17 | struct addrinfo *res; 18 | const struct addrinfo hints = { .ai_family = AF_INET }; 19 | int error, sock; 20 | 21 | /* resolve the domain name into a list of addresses */ 22 | error = getaddrinfo("www.example.com", NULL, &hints, &result); 23 | if (error != 0) { 24 | fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error)); 25 | return EXIT_FAILURE; 26 | } 27 | if((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { 28 | perror("socket"); 29 | return EXIT_FAILURE; 30 | } 31 | struct sockaddr_in6 a = { .sin6_family = AF_INET6, 32 | .sin6_port = htons(80) }; 33 | v4_to_v6(&((struct sockaddr_in *)result->ai_addr)->sin_addr, &a.sin6_addr); 34 | freeaddrinfo(result); 35 | 36 | if((error = connect(sock, (struct sockaddr *)&a, sizeof(a))) == -1) { 37 | perror("connect"); 38 | return EXIT_FAILURE; 39 | } 40 | 41 | return EXIT_SUCCESS; 42 | } 43 | -------------------------------------------------------------------------------- /tools/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This is an actually-safe install command which installs the new 4 | # file atomically in the new location, rather than overwriting 5 | # existing files. 6 | # 7 | 8 | usage() { 9 | printf "usage: %s [-D] [-l] [-m mode] src dest\n" "$0" 1>&2 10 | exit 1 11 | } 12 | 13 | mkdirp= 14 | symlink= 15 | mode=755 16 | 17 | while getopts Dlm: name ; do 18 | case "$name" in 19 | D) mkdirp=yes ;; 20 | l) symlink=yes ;; 21 | m) mode=$OPTARG ;; 22 | ?) usage ;; 23 | esac 24 | done 25 | shift $(($OPTIND - 1)) 26 | 27 | test "$#" -eq 2 || usage 28 | src=$1 29 | dst=$2 30 | tmp="$dst.tmp.$$" 31 | 32 | case "$dst" in 33 | */) printf "%s: %s ends in /\n", "$0" "$dst" 1>&2 ; exit 1 ;; 34 | esac 35 | 36 | set -C 37 | set -e 38 | 39 | if test "$mkdirp" ; then 40 | umask 022 41 | case "$2" in 42 | */*) mkdir -p "${dst%/*}" ;; 43 | esac 44 | fi 45 | 46 | trap 'rm -f "$tmp"' EXIT INT QUIT TERM HUP 47 | 48 | umask 077 49 | 50 | if test "$symlink" ; then 51 | ln -s "$1" "$tmp" 52 | else 53 | cat < "$1" > "$tmp" 54 | chmod "$mode" "$tmp" 55 | fi 56 | 57 | mv -f "$tmp" "$2" 58 | test -d "$2" && { 59 | rm -f "$2/$tmp" 60 | printf "%s: %s is a directory\n" "$0" "$dst" 1>&2 61 | exit 1 62 | } 63 | 64 | exit 0 65 | -------------------------------------------------------------------------------- /tools/version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if test -d .git ; then 4 | if type git >/dev/null 2>&1 ; then 5 | git describe --tags --match 'v[0-9]*' 2>/dev/null \ 6 | | sed -e 's/^v//' -e 's/-/-git-/' 7 | else 8 | sed 's/$/-git/' < VERSION 9 | fi 10 | else 11 | cat VERSION 12 | fi 13 | --------------------------------------------------------------------------------