├── .gitignore ├── AUTHORS ├── COPYING ├── Makefile ├── README ├── TODO ├── VERSION ├── configure ├── src ├── allocator_thread.c ├── allocator_thread.h ├── common.c ├── common.h ├── core.c ├── core.h ├── debug.c ├── debug.h ├── hash.c ├── hash.h ├── hostsreader.c ├── ip_type.c ├── ip_type.h ├── libproxychains.c ├── main.c ├── mutex.h ├── nameinfo.c ├── proxychains.conf ├── proxyresolv ├── version.c └── version.h ├── tests ├── test_getaddrinfo.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 | *.bz2 3 | *.xz 4 | *.o 5 | *.so 6 | *.la 7 | *.lo 8 | .deps/ 9 | .libs/ 10 | *.rcb 11 | *.out 12 | *~ 13 | *.patch 14 | 15 | # Autoconf stuff 16 | libtool 17 | config.* 18 | stamp-h 19 | -------------------------------------------------------------------------------- /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 | 16 | SRCS = $(sort $(wildcard src/*.c)) 17 | OBJS = $(SRCS:.c=.o) 18 | LOBJS = src/nameinfo.o src/version.o \ 19 | src/core.o src/common.o src/libproxychains.o \ 20 | src/allocator_thread.o src/ip_type.o \ 21 | src/hostsreader.o src/hash.o src/debug.o 22 | 23 | GENH = src/version.h 24 | 25 | CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe 26 | NO_AS_NEEDED = -Wl,--no-as-needed 27 | LIBDL = -ldl 28 | LDFLAGS = -fPIC $(NO_AS_NEEDED) $(LIBDL) -lpthread 29 | INC = 30 | PIC = -fPIC 31 | AR = $(CROSS_COMPILE)ar 32 | RANLIB = $(CROSS_COMPILE)ranlib 33 | 34 | LDSO_SUFFIX = so 35 | LD_SET_SONAME = -Wl,-soname= 36 | INSTALL = ./tools/install.sh 37 | 38 | LDSO_PATHNAME = libproxychains4.$(LDSO_SUFFIX) 39 | 40 | SHARED_LIBS = $(LDSO_PATHNAME) 41 | ALL_LIBS = $(SHARED_LIBS) 42 | PXCHAINS = proxychains4 43 | ALL_TOOLS = $(PXCHAINS) 44 | ALL_CONFIGS = src/proxychains.conf 45 | 46 | -include config.mak 47 | 48 | CFLAGS+=$(USER_CFLAGS) $(MAC_CFLAGS) 49 | CFLAGS_MAIN=-DLIB_DIR=\"$(libdir)\" -DSYSCONFDIR=\"$(sysconfdir)\" -DDLL_NAME=\"$(LDSO_PATHNAME)\" 50 | 51 | 52 | all: $(ALL_LIBS) $(ALL_TOOLS) 53 | 54 | install: install-libs install-tools 55 | 56 | $(DESTDIR)$(bindir)/%: % 57 | $(INSTALL) -D -m 755 $< $@ 58 | 59 | $(DESTDIR)$(libdir)/%: % 60 | $(INSTALL) -D -m 644 $< $@ 61 | 62 | $(DESTDIR)$(sysconfdir)/%: src/% 63 | $(INSTALL) -D -m 644 $< $@ 64 | 65 | install-libs: $(ALL_LIBS:%=$(DESTDIR)$(libdir)/%) 66 | install-tools: $(ALL_TOOLS:%=$(DESTDIR)$(bindir)/%) 67 | install-config: $(ALL_CONFIGS:src/%=$(DESTDIR)$(sysconfdir)/%) 68 | 69 | clean: 70 | rm -f $(ALL_LIBS) 71 | rm -f $(ALL_TOOLS) 72 | rm -f $(OBJS) 73 | rm -f $(GENH) 74 | 75 | src/version.h: $(wildcard VERSION .git) 76 | printf '#define VERSION "%s"\n' "$$(sh tools/version.sh)" > $@ 77 | 78 | src/version.o: src/version.h 79 | 80 | %.o: %.c 81 | $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_MAIN) $(INC) $(PIC) -c -o $@ $< 82 | 83 | $(LDSO_PATHNAME): $(LOBJS) 84 | $(CC) $(LDFLAGS) $(LD_SET_SONAME)$(LDSO_PATHNAME) $(USER_LDFLAGS) \ 85 | -shared -o $@ $(LOBJS) 86 | 87 | $(ALL_TOOLS): $(OBJS) 88 | $(CC) src/main.o src/common.o $(USER_LDFLAGS) -o $(PXCHAINS) 89 | 90 | 91 | .PHONY: all clean install install-config install-libs install-tools 92 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ProxyChains-NG ver 4.12 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. 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.12 56 | - fix several build issues 57 | - for MAC 58 | - with -pie 59 | - with custom CC 60 | - compatibility fix for some GUI apps (8870140) 61 | - compatibility fix for some HTTP proxies (cf9a16d) 62 | - fix several warnings for cleaner build on debian 63 | - fix random_chain on OSX (0f6b226) 64 | 65 | Version 4.11 66 | - preliminary IPv6 support 67 | - fixed bug in hostsreader 68 | - preliminary support for usage on OpenBSD (caveat emptor) 69 | 70 | Version 4.10 71 | - fix regression in linking order with custom LDFLAGS 72 | - fix segfault in DNS mapping code in programs with > ~400 different lookups 73 | 74 | Version 4.9 75 | - fix a security issue CVE-2015-3887 76 | - add sendto hook to handle MSG_FASTOPEN flag 77 | - replace problematic hostentdb with hostsreader 78 | - fix compilation on OpenBSD (although doesn't work there) 79 | 80 | Version 4.8.1: 81 | - fix regression in 4.8 install-config Makefile target 82 | 83 | Version 4.8: 84 | - fix for odd cornercase where getaddrinfo was used with AI_NUMERICHOST 85 | to test for a numeric ip instead of resolving it (fixes nmap). 86 | - allow usage with programs that rely on LD_PRELOAD themselves 87 | - reject wrong entries in config file 88 | - print version number on startup 89 | 90 | Version 4.7: 91 | - new round_robin chaintype by crass. 92 | - fix bug with lazy allocation when GCC constructor was not used. 93 | - new configure flag --fat-binary to create a "fat" binary/library on OS X 94 | - return EBADF rather than EINTR in close hook. 95 | it's legal for a program to retry close() calls when they receive 96 | EINTR, which could cause an infinite loop, as seen in chromium. 97 | 98 | Version 4.6: 99 | - some cosmetic fixes to Makefile, fix a bug when non-numeric ip was 100 | used as proxy server address. 101 | 102 | Version 4.5: 103 | - hook close() to prevent OpenSSH from messing with internal infrastructure. 104 | this caused ssh client to segfault when proxified. 105 | 106 | Version 4.4: 107 | - FreeBSD port 108 | - fixes some installation issues on Debian and Mac. 109 | 110 | Version 4.3: 111 | - fixes programs that do dns-lookups in child processes (fork()ed), 112 | like irssi. to achieve this, support for compilation without pthreads 113 | was sacrified. 114 | - fixes thread safety for gethostent() calls. 115 | - improved DNS handling speed, since hostent db is cached. 116 | 117 | Version 4.2: 118 | - fixes compilation issues with ubuntu 12.04 toolchain 119 | - fixes segfault in rare codepath 120 | 121 | Version 4.1 122 | - support for mac os x (all archs) 123 | - all internal functions are threadsafe when compiled with -DTHREAD_SAFE 124 | (default). 125 | 126 | Version 4.0 127 | - replaced dnsresolver script (which required a dynamically linked "dig" 128 | binary to be present) with remote DNS lookup. 129 | this speeds up any operation involving DNS, as the old script had to use TCP. 130 | additionally it allows to use .onion urls when used with TOR. 131 | - removed broken autoconf build system with a simple Makefile. 132 | there's a ./configure script though for convenience. 133 | it also adds support for a config file passed via command line switches/ 134 | environment variables. 135 | 136 | Version 3.0 137 | - support for DNS resolving through proxy 138 | supports SOCKS4, SOCKS5 and HTTP CONNECT proxy servers. 139 | Auth-types: socks - "user/pass" , http - "basic". 140 | 141 | When to use it ? 142 | 1) When the only way to get "outside" from your LAN is through proxy server. 143 | 2) To get out from behind restrictive firewall which filters outgoing ports. 144 | 3) To use two (or more) proxies in chain: 145 | like: your_host <--> proxy1 <--> proxy2 <--> target_host 146 | 4) To "proxify" some program with no proxy support built-in (like telnet) 147 | 5) Access intranet from outside via proxy. 148 | 6) To use DNS behind proxy. 149 | 7) To access hidden tor onion services. 150 | 151 | Some cool features: 152 | 153 | * This program can mix different proxy types in the same chain 154 | like: your_host <-->socks5 <--> http <--> socks4 <--> target_host 155 | * Different chaining options supported 156 | random order from the list ( user defined length of chain ). 157 | exact order (as they appear in the list ) 158 | dynamic order (smart exclude dead proxies from chain) 159 | * You can use it with most TCP client applications, possibly even network 160 | scanners, as long as they use standard libc functionality. 161 | pcap based scanning does not work. 162 | * You can use it with servers, like squid, sendmail, or whatever. 163 | * DNS resolving through proxy. 164 | 165 | 166 | Configuration: 167 | -------------- 168 | 169 | proxychains looks for config file in following order: 170 | 1) file listed in environment variable PROXYCHAINS_CONF_FILE or 171 | provided as a -f argument to proxychains script or binary. 172 | 2) ./proxychains.conf 173 | 3) $(HOME)/.proxychains/proxychains.conf 174 | 4) $(sysconfdir)/proxychains.conf ** 175 | 176 | ** usually /etc/proxychains.conf 177 | 178 | Usage Example: 179 | 180 | $ proxychains telnet targethost.com 181 | 182 | in this example it will run telnet through proxy(or chained proxies) 183 | specified by proxychains.conf 184 | 185 | Usage Example: 186 | 187 | $ proxychains -f /etc/proxychains-other.conf telnet targethost2.com 188 | 189 | in this example it will use different configuration file then proxychains.conf 190 | to connect to targethost2.com host. 191 | 192 | Usage Example: 193 | 194 | $ proxyresolv targethost.com 195 | 196 | in this example it will resolve targethost.com through proxy(or chained proxies) 197 | specified by proxychains.conf 198 | 199 | Known Problems: 200 | --------------- 201 | - newer versions of nmap try to determine the network interface to use 202 | even if it's not needed (like when doing simple syn scans which use the 203 | standard POSIX socket API. this results in errors when proxychains hands 204 | out an ip address to a reserved address space. 205 | possible workarounds: disable proxy_dns, use a numeric ip, or use nmap's 206 | native support for SOCKS proxies. 207 | 208 | - Mac OS X 10.11 (El Capitan) ships with a new security feature called SIP 209 | that prevents hooking of system apps. 210 | workarounds are to partially disable SIP by issuing 211 | csrutil enable --without debug in recovery mode, 212 | or to copy the system binary into the home directory and run it from there. 213 | see github issue #78 for details. 214 | 215 | - the glibc dynlinker has a bug or security feature that inhibits dlopen()ed 216 | modules from being subject to the same dlsym hooks as installed for the main 217 | program. this mainly affects scripting languages such as perl or python 218 | that heavily rely on dlopen() for modules written in C to work. 219 | there are unconfirmed reports that it works as root though. 220 | musl libc is unaffected from the bug. 221 | 222 | 223 | Community: 224 | ---------- 225 | #proxychains on irc.freenode.net 226 | 227 | Donations: 228 | ---------- 229 | bitcoins donations are welcome - please send to this address: 230 | 1C9LBpuy56veBqw5N33sZMoZW8mwCw3tPh 231 | 232 | -------------------------------------------------------------------------------- /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.12 2 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | prefix=/usr/local 4 | OUR_CPPFLAGS= 5 | 6 | # Get a temporary filename 7 | i=0 8 | set -C 9 | while : ; do i=$(($i+1)) 10 | tmpc="./conf$$-$PPID-$i.c" 11 | 2>|/dev/null > "$tmpc" && break 12 | test "$i" -gt 50 && fail "$0: cannot create temporary file $tmpc" 13 | done 14 | set +C 15 | trap 'rm "$tmpc"' EXIT INT QUIT TERM HUP 16 | 17 | ismac() { 18 | uname -s | grep Darwin >/dev/null 19 | } 20 | 21 | isx86_64() { 22 | uname -m | grep -i X86_64 >/dev/null 23 | } 24 | 25 | isbsd() { 26 | uname -s | grep BSD >/dev/null 27 | } 28 | 29 | isopenbsd() { 30 | uname -s | grep OpenBSD >/dev/null 31 | } 32 | 33 | check_compile() { 34 | printf "checking %s ... " "$1" 35 | printf "$3" > "$tmpc" 36 | local res=0 37 | $CC $OUR_CPPFLAGS $CPPFLAGS $2 $CFLAGS -c "$tmpc" -o /dev/null >/dev/null 2>&1 \ 38 | || res=1 39 | test x$res = x0 && \ 40 | { printf "yes\n" ; test x"$2" = x || OUR_CPPFLAGS="$OUR_CPPFLAGS $2" ; } \ 41 | || printf "no\n" 42 | return $res 43 | } 44 | 45 | check_define() { 46 | printf "checking whether \$CC defines %s ... " "$1" 47 | local res=1 48 | $CC $OUR_CPPFLAGS $CPPFLAGS $CFLAGS -dM -E - /dev/null && res=0 49 | test x$res = x0 && printf "yes\n" || printf "no\n" 50 | return $res 51 | } 52 | 53 | check_compile_run() { 54 | printf "checking %s ... " "$1" 55 | printf "$2" > "$tmpc" 56 | local res=0 57 | $CC $OUR_CPPFLAGS $CPPFLAGS $CFLAGS "$tmpc" -o "$tmpc".out >/dev/null 2>&1 \ 58 | || res=1 59 | test x$res = x0 && { "$tmpc".out || res=1 ; } 60 | rm -f "$tmpc".out 61 | test x$res = x0 && printf "yes\n" || printf "no\n" 62 | return $res 63 | } 64 | 65 | usage() { 66 | echo "supported arguments" 67 | echo "--prefix=/path default: $prefix" 68 | echo "--exec_prefix=/path default: $prefix/bin" 69 | echo "--bindir=/path default: $prefix/bin" 70 | echo "--libdir=/path default: $prefix/lib" 71 | echo "--includedir=/path default: $prefix/include" 72 | echo "--sysconfdir=/path default: $prefix/etc" 73 | echo "--ignore-cve default: no" 74 | echo " if set to yes ignores CVE-2015-3887 and makes it possible" 75 | echo " to preload from current dir (insecure)" 76 | ismac && isx86_64 && echo "--fat-binary : build for both i386 and x86_64 architectures on 64-bit Macs" 77 | echo "--help : show this text" 78 | exit 1 79 | } 80 | 81 | spliteq() { 82 | arg=$1 83 | echo "${arg#*=}" 84 | #alternatives echo "$arg" | cut -d= -f2- 85 | # or echo "$arg" | sed 's/[^=]*=//' 86 | } 87 | 88 | fat_binary= 89 | ignore_cve=no 90 | parsearg() { 91 | case "$1" in 92 | --prefix=*) prefix=`spliteq $1`;; 93 | --exec_prefix=*) exec_prefix=`spliteq $1`;; 94 | --bindir=*) bindir=`spliteq $1`;; 95 | --libdir=*) libdir=`spliteq $1`;; 96 | --includedir=*) includedir=`spliteq $1`;; 97 | --sysconfdir=*) sysconfdir=`spliteq $1`;; 98 | --ignore-cve) ignore_cve=1;; 99 | --ignore-cve=*) ignore_cve=`spliteq $1`;; 100 | --fat-binary) fat_binary=1;; 101 | --help) usage;; 102 | esac 103 | } 104 | 105 | while true ; do 106 | case $1 in 107 | -*) parsearg "$1"; shift;; 108 | *) break ;; 109 | esac 110 | done 111 | 112 | if [ -z "$exec_prefix" ] ; then 113 | exec_prefix=$prefix 114 | fi 115 | 116 | if [ -z "$libdir" ] ; then 117 | libdir=$prefix/lib 118 | fi 119 | 120 | if [ -z "$includedir" ] ; then 121 | includedir=$prefix/include 122 | fi 123 | 124 | if [ -z "$sysconfdir" ] ; then 125 | sysconfdir=$prefix/etc 126 | fi 127 | 128 | if [ -z "$bindir" ] ; then 129 | bindir=$exec_prefix/bin 130 | fi 131 | 132 | if [ -z "$CC" ] ; then 133 | CC=cc 134 | fi 135 | 136 | check_compile 'whether netinet/in.h defines s6_addr16' "" \ 137 | '#include \nint main(int a, char**c){struct in6_addr x={.s6_addr32[0]=a};return x.s6_addr16[0]; }' \ 138 | || { 139 | check_compile 'whether netinet/in.h defines __u6_addr.__u6_addr16' \ 140 | '-Ds6_addr16=__u6_addr.__u6_addr16 -Ds6_addr32=__u6_addr.__u6_addr32' \ 141 | '#include \nint main(int a, char**c){struct in6_addr x={.s6_addr32[0]=a};return x.s6_addr16[0]; }' 142 | } 143 | 144 | check_define __OpenBSD__ && \ 145 | check_compile_run 'whether OpenBSDs fclose() (illegally) calls close()' \ 146 | '#include \n#include\nint close(int x){exit(0);}int main(){fclose(stdin);return 1;}' && \ 147 | OUR_CPPFLAGS="$OUR_CPPFLAGS -DBROKEN_FCLOSE" 148 | 149 | echo "CC=$CC">config.mak 150 | [ -z "$CPPFLAGS" ] || echo "CPPFLAGS=$CPPFLAGS">>config.mak 151 | [ -z "$CFLAGS" ] || echo "USER_CFLAGS=$CFLAGS">>config.mak 152 | [ -z "$LDFLAGS" ] || echo "USER_LDFLAGS=$LDFLAGS">>config.mak 153 | echo prefix=$prefix>>config.mak 154 | echo exec_prefix=$exec_prefix>>config.mak 155 | echo bindir=$bindir>>config.mak 156 | echo libdir=$libdir>>config.mak 157 | echo includedir=$includedir>>config.mak 158 | echo sysconfdir=$sysconfdir>>config.mak 159 | [ "$ignore_cve" = "no" ] && echo "CPPFLAGS+= -DSUPER_SECURE">>config.mak 160 | [ -z "$OUR_CPPFLAGS" ] || echo "CPPFLAGS+= $OUR_CPPFLAGS" >>config.mak 161 | make_cmd=make 162 | if ismac ; then 163 | echo NO_AS_NEEDED=>>config.mak 164 | echo LDSO_SUFFIX=dylib>>config.mak 165 | echo MAC_CFLAGS+=-DIS_MAC=1>>config.mak 166 | if isx86_64 && [ "$fat_binary" = 1 ] ; then 167 | echo "Configuring a fat binary for i386 and x86_64" 168 | echo MAC_CFLAGS+=-arch i386 -arch x86_64>>config.mak 169 | echo LDFLAGS+=-arch i386 -arch x86_64>>config.mak 170 | fi 171 | echo LD_SET_SONAME=-Wl,-install_name,>>config.mak 172 | elif isbsd ; then 173 | echo LIBDL=>>config.mak 174 | echo "CFLAGS+=-DIS_BSD">>config.mak 175 | isopenbsd && echo "CFLAGS+=-DIS_OPENBSD">>config.mak 176 | make_cmd=gmake 177 | fi 178 | 179 | echo "Done, now run $make_cmd && $make_cmd install" 180 | -------------------------------------------------------------------------------- /src/allocator_thread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "allocator_thread.h" 13 | #include "debug.h" 14 | #include "ip_type.h" 15 | #include "mutex.h" 16 | #include "hash.h" 17 | 18 | /* stuff for our internal translation table */ 19 | 20 | typedef struct { 21 | uint32_t hash; 22 | char* string; 23 | } string_hash_tuple; 24 | 25 | typedef struct { 26 | uint32_t counter; 27 | uint32_t capa; 28 | string_hash_tuple** list; 29 | } internal_ip_lookup_table; 30 | 31 | static void *dumpstring(char* s, size_t len) { 32 | char* p = malloc(len); 33 | if(p) memcpy(p, s, len); 34 | return p; 35 | } 36 | 37 | pthread_mutex_t internal_ips_lock; 38 | internal_ip_lookup_table *internal_ips = NULL; 39 | internal_ip_lookup_table internal_ips_buf; 40 | 41 | uint32_t index_from_internal_ip(ip_type4 internalip) { 42 | PFUNC(); 43 | ip_type4 tmp = internalip; 44 | uint32_t ret; 45 | ret = tmp.octet[3] + (tmp.octet[2] << 8) + (tmp.octet[1] << 16); 46 | ret -= 1; 47 | return ret; 48 | } 49 | 50 | char *string_from_internal_ip(ip_type4 internalip) { 51 | PFUNC(); 52 | char *res = NULL; 53 | uint32_t index = index_from_internal_ip(internalip); 54 | if(index < internal_ips->counter) 55 | res = internal_ips->list[index]->string; 56 | return res; 57 | } 58 | 59 | extern unsigned int remote_dns_subnet; 60 | ip_type4 make_internal_ip(uint32_t index) { 61 | ip_type4 ret; 62 | index++; // so we can start at .0.0.1 63 | if(index > 0xFFFFFF) 64 | return ip_type_invalid.addr.v4; 65 | ret.octet[0] = remote_dns_subnet & 0xFF; 66 | ret.octet[1] = (index & 0xFF0000) >> 16; 67 | ret.octet[2] = (index & 0xFF00) >> 8; 68 | ret.octet[3] = index & 0xFF; 69 | return ret; 70 | } 71 | 72 | static ip_type4 ip_from_internal_list(char* name, size_t len) { 73 | uint32_t hash = dalias_hash((char *) name); 74 | size_t i; 75 | ip_type4 res; 76 | void* new_mem; 77 | // see if we already have this dns entry saved. 78 | if(internal_ips->counter) { 79 | for(i = 0; i < internal_ips->counter; i++) { 80 | if(internal_ips->list[i]->hash == hash && !strcmp(name, internal_ips->list[i]->string)) { 81 | res = make_internal_ip(i); 82 | PDEBUG("got cached ip for %s\n", name); 83 | goto have_ip; 84 | } 85 | } 86 | } 87 | // grow list if needed. 88 | if(internal_ips->capa < internal_ips->counter + 1) { 89 | PDEBUG("realloc\n"); 90 | new_mem = realloc(internal_ips->list, (internal_ips->capa + 16) * sizeof(void *)); 91 | if(new_mem) { 92 | internal_ips->capa += 16; 93 | internal_ips->list = new_mem; 94 | } else { 95 | oom: 96 | PDEBUG("out of mem\n"); 97 | goto err_plus_unlock; 98 | } 99 | } 100 | 101 | res = make_internal_ip(internal_ips->counter); 102 | if(res.as_int == ip_type_invalid.addr.v4.as_int) 103 | goto err_plus_unlock; 104 | 105 | string_hash_tuple tmp = { 0 }; 106 | new_mem = dumpstring((char*) &tmp, sizeof(string_hash_tuple)); 107 | if(!new_mem) 108 | goto oom; 109 | 110 | PDEBUG("creating new entry %d for ip of %s\n", (int) internal_ips->counter, name); 111 | 112 | internal_ips->list[internal_ips->counter] = new_mem; 113 | internal_ips->list[internal_ips->counter]->hash = hash; 114 | 115 | new_mem = dumpstring((char*) name, len + 1); 116 | 117 | if(!new_mem) { 118 | internal_ips->list[internal_ips->counter] = 0; 119 | goto oom; 120 | } 121 | internal_ips->list[internal_ips->counter]->string = new_mem; 122 | 123 | internal_ips->counter += 1; 124 | 125 | have_ip: 126 | 127 | return res; 128 | err_plus_unlock: 129 | 130 | PDEBUG("return err\n"); 131 | return ip_type_invalid.addr.v4; 132 | } 133 | 134 | /* stuff for communication with the allocator thread */ 135 | 136 | enum at_msgtype { 137 | ATM_GETIP, 138 | ATM_GETNAME, 139 | ATM_EXIT, 140 | }; 141 | 142 | enum at_direction { 143 | ATD_SERVER = 0, 144 | ATD_CLIENT, 145 | ATD_MAX, 146 | }; 147 | 148 | struct at_msghdr { 149 | enum at_msgtype msgtype; 150 | size_t datalen; 151 | }; 152 | 153 | static pthread_t allocator_thread; 154 | static pthread_attr_t allocator_thread_attr; 155 | int req_pipefd[2]; 156 | int resp_pipefd[2]; 157 | 158 | static int wait_data(int readfd) { 159 | PFUNC(); 160 | fd_set fds; 161 | FD_ZERO(&fds); 162 | FD_SET(readfd, &fds); 163 | int ret; 164 | while((ret = select(readfd+1, &fds, NULL, NULL, NULL)) <= 0) { 165 | if(ret < 0) { 166 | int e = errno; 167 | if(e == EINTR) continue; 168 | #ifdef __GLIBC__ 169 | char emsg[1024]; 170 | char* x = strerror_r(errno, emsg, sizeof emsg); 171 | dprintf(2, "select2: %s\n", x); 172 | #endif 173 | return 0; 174 | } 175 | } 176 | return 1; 177 | } 178 | 179 | static int trywrite(int fd, void* buf, size_t bytes) { 180 | ssize_t ret; 181 | unsigned char *out = buf; 182 | again: 183 | ret = write(fd, out, bytes); 184 | switch(ret) { 185 | case -1: 186 | if(errno == EINTR) goto again; 187 | case 0: 188 | return 0; 189 | default: 190 | if(ret == bytes || !bytes) return 1; 191 | out += ret; 192 | bytes -= ret; 193 | goto again; 194 | } 195 | } 196 | 197 | static int sendmessage(enum at_direction dir, struct at_msghdr *hdr, void* data) { 198 | static int* destfd[ATD_MAX] = { [ATD_SERVER] = &req_pipefd[1], [ATD_CLIENT] = &resp_pipefd[1] }; 199 | int ret = trywrite(*destfd[dir], hdr, sizeof *hdr); 200 | if(ret && hdr->datalen) { 201 | assert(hdr->datalen <= MSG_LEN_MAX); 202 | ret = trywrite(*destfd[dir], data, hdr->datalen); 203 | } 204 | return ret; 205 | } 206 | 207 | static int tryread(int fd, void* buf, size_t bytes) { 208 | ssize_t ret; 209 | unsigned char *out = buf; 210 | again: 211 | ret = read(fd, out, bytes); 212 | switch(ret) { 213 | case -1: 214 | if(errno == EINTR) goto again; 215 | case 0: 216 | return 0; 217 | default: 218 | if(ret == bytes || !bytes) return 1; 219 | out += ret; 220 | bytes -= ret; 221 | goto again; 222 | } 223 | } 224 | 225 | static int getmessage(enum at_direction dir, struct at_msghdr *hdr, void* data) { 226 | static int* readfd[ATD_MAX] = { [ATD_SERVER] = &req_pipefd[0], [ATD_CLIENT] = &resp_pipefd[0] }; 227 | ssize_t ret; 228 | if((ret = wait_data(*readfd[dir]))) { 229 | if(!tryread(*readfd[dir], hdr, sizeof *hdr)) 230 | return 0; 231 | assert(hdr->datalen <= MSG_LEN_MAX); 232 | if(hdr->datalen) { 233 | ret = tryread(*readfd[dir], data, hdr->datalen); 234 | } 235 | } 236 | return ret; 237 | } 238 | 239 | static void* threadfunc(void* x) { 240 | (void) x; 241 | int ret; 242 | struct at_msghdr msg; 243 | union { 244 | char host[MSG_LEN_MAX]; 245 | ip_type4 ip; 246 | } readbuf; 247 | while((ret = getmessage(ATD_SERVER, &msg, &readbuf))) { 248 | switch(msg.msgtype) { 249 | case ATM_GETIP: 250 | /* client wants an ip for a DNS name. iterate our list and check if we have an existing entry. 251 | * if not, create a new one. */ 252 | readbuf.ip = ip_from_internal_list(readbuf.host, msg.datalen - 1); 253 | msg.datalen = sizeof(ip_type4); 254 | break; 255 | case ATM_GETNAME: { 256 | char *host = string_from_internal_ip(readbuf.ip); 257 | if(host) { 258 | size_t l = strlen(host); 259 | assert(l < MSG_LEN_MAX); 260 | memcpy(readbuf.host, host, l + 1); 261 | msg.datalen = l + 1; 262 | } 263 | break; 264 | } 265 | case ATM_EXIT: 266 | return 0; 267 | default: 268 | abort(); 269 | } 270 | ret = sendmessage(ATD_CLIENT, &msg, &readbuf); 271 | } 272 | return 0; 273 | } 274 | 275 | /* API to access the internal ip mapping */ 276 | 277 | ip_type4 at_get_ip_for_host(char* host, size_t len) { 278 | ip_type4 readbuf; 279 | MUTEX_LOCK(&internal_ips_lock); 280 | if(len > MSG_LEN_MAX) goto inv; 281 | struct at_msghdr msg = {.msgtype = ATM_GETIP, .datalen = len + 1 }; 282 | if(sendmessage(ATD_SERVER, &msg, host) && 283 | getmessage(ATD_CLIENT, &msg, &readbuf)); 284 | else { 285 | inv: 286 | readbuf = ip_type_invalid.addr.v4; 287 | } 288 | MUTEX_UNLOCK(&internal_ips_lock); 289 | return readbuf; 290 | } 291 | 292 | size_t at_get_host_for_ip(ip_type4 ip, char* readbuf) { 293 | struct at_msghdr msg = {.msgtype = ATM_GETNAME, .datalen = sizeof(ip_type4) }; 294 | size_t res = 0; 295 | MUTEX_LOCK(&internal_ips_lock); 296 | if(sendmessage(ATD_SERVER, &msg, &ip) && getmessage(ATD_CLIENT, &msg, readbuf)) { 297 | if((ptrdiff_t) msg.datalen <= 0) res = 0; 298 | else res = msg.datalen - 1; 299 | } 300 | MUTEX_UNLOCK(&internal_ips_lock); 301 | return res; 302 | } 303 | 304 | 305 | static void initpipe(int* fds) { 306 | if(pipe(fds) == -1) { 307 | perror("pipe"); 308 | exit(1); 309 | } 310 | } 311 | 312 | /* initialize with pointers to shared memory. these will 313 | * be used to place responses and arguments */ 314 | void at_init(void) { 315 | PFUNC(); 316 | MUTEX_INIT(&internal_ips_lock); 317 | internal_ips = &internal_ips_buf; 318 | memset(internal_ips, 0, sizeof *internal_ips); 319 | initpipe(req_pipefd); 320 | initpipe(resp_pipefd); 321 | pthread_attr_init(&allocator_thread_attr); 322 | pthread_attr_setstacksize(&allocator_thread_attr, 16 * 1024); 323 | pthread_create(&allocator_thread, &allocator_thread_attr, threadfunc, 0); 324 | } 325 | 326 | void at_close(void) { 327 | PFUNC(); 328 | const int msg = ATM_EXIT; 329 | write(req_pipefd[1], &msg, sizeof(int)); 330 | pthread_join(allocator_thread, NULL); 331 | close(req_pipefd[0]); 332 | close(req_pipefd[1]); 333 | close(resp_pipefd[0]); 334 | close(resp_pipefd[1]); 335 | pthread_attr_destroy(&allocator_thread_attr); 336 | MUTEX_DESTROY(&internal_ips_lock); 337 | } 338 | -------------------------------------------------------------------------------- /src/allocator_thread.h: -------------------------------------------------------------------------------- 1 | #ifndef ALLOCATOR_THREAD_H 2 | #define ALLOCATOR_THREAD_H 3 | 4 | #include 5 | #include "ip_type.h" 6 | 7 | #define MSG_LEN_MAX 256 8 | 9 | extern int req_pipefd[2]; 10 | extern int resp_pipefd[2]; 11 | 12 | void at_init(void); 13 | void at_close(void); 14 | size_t at_get_host_for_ip(ip_type4 ip, char* readbuf); 15 | ip_type4 at_get_ip_for_host(char* host, size_t len); 16 | 17 | //RcB: DEP "allocator_thread.c" 18 | #endif 19 | 20 | -------------------------------------------------------------------------------- /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 | // stolen from libulz (C) rofl0r 27 | void pc_stringfromipv4(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes) { 28 | unsigned char *p; 29 | char *o = outbuf_16_bytes; 30 | unsigned char n; 31 | for(p = ip_buf_4_bytes; p < ip_buf_4_bytes + 4; p++) { 32 | n = *p; 33 | if(*p >= 100) { 34 | if(*p >= 200) 35 | *(o++) = '2'; 36 | else 37 | *(o++) = '1'; 38 | n %= 100; 39 | } 40 | if(*p >= 10) { 41 | *(o++) = (n / 10) + '0'; 42 | n %= 10; 43 | } 44 | *(o++) = n + '0'; 45 | *(o++) = '.'; 46 | } 47 | o[-1] = 0; 48 | } 49 | 50 | static int check_path(char *path) { 51 | if(!path) 52 | return 0; 53 | return access(path, R_OK) != -1; 54 | } 55 | 56 | char *get_config_path(char* default_path, char* pbuf, size_t bufsize) { 57 | char buf[512]; 58 | // top priority: user defined path 59 | char *path = default_path; 60 | if(check_path(path)) 61 | goto have; 62 | 63 | // priority 1: env var PROXYCHAINS_CONF_FILE 64 | path = getenv(PROXYCHAINS_CONF_FILE_ENV_VAR); 65 | if(check_path(path)) 66 | goto have; 67 | 68 | // priority 2; proxychains conf in actual dir 69 | path = getcwd(buf, sizeof(buf)); 70 | snprintf(pbuf, bufsize, "%s/%s", path, PROXYCHAINS_CONF_FILE); 71 | path = pbuf; 72 | if(check_path(path)) 73 | goto have; 74 | 75 | // priority 3; $HOME/.proxychains/proxychains.conf 76 | path = getenv("HOME"); 77 | snprintf(pbuf, bufsize, "%s/.proxychains/%s", path, PROXYCHAINS_CONF_FILE); 78 | path = pbuf; 79 | if(check_path(path)) 80 | goto have; 81 | 82 | // priority 4: $SYSCONFDIR/proxychains.conf 83 | path = SYSCONFDIR "/" PROXYCHAINS_CONF_FILE; 84 | if(check_path(path)) 85 | goto have; 86 | 87 | // priority 5: /etc/proxychains.conf 88 | path = "/etc/" PROXYCHAINS_CONF_FILE; 89 | if(check_path(path)) 90 | goto have; 91 | 92 | perror("couldnt find configuration file"); 93 | exit(1); 94 | 95 | return NULL; 96 | have: 97 | return path; 98 | } 99 | -------------------------------------------------------------------------------- /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 | 21 | //RcB: DEP "common.c" 22 | #endif 23 | -------------------------------------------------------------------------------- /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 | #include 38 | 39 | #ifdef ANDROID 40 | #include 41 | #endif 42 | 43 | #include "core.h" 44 | #include "common.h" 45 | #include "allocator_thread.h" 46 | 47 | extern int tcp_read_time_out; 48 | extern int tcp_connect_time_out; 49 | extern int proxychains_quiet_mode; 50 | extern unsigned int proxychains_proxy_offset; 51 | extern unsigned int remote_dns_subnet; 52 | 53 | static int poll_retry(struct pollfd *fds, nfds_t nfsd, int timeout) { 54 | int ret; 55 | int time_remain = timeout; 56 | int time_elapsed = 0; 57 | 58 | struct timeval start_time; 59 | struct timeval tv; 60 | 61 | gettimeofday(&start_time, NULL); 62 | 63 | do { 64 | //printf("Retry %d\n", time_remain); 65 | ret = poll(fds, nfsd, time_remain); 66 | gettimeofday(&tv, NULL); 67 | time_elapsed = ((tv.tv_sec - start_time.tv_sec) * 1000 + (tv.tv_usec - start_time.tv_usec) / 1000); 68 | //printf("Time elapsed %d\n", time_elapsed); 69 | time_remain = timeout - time_elapsed; 70 | } while(ret == -1 && errno == EINTR && time_remain > 0); 71 | 72 | //if (ret == -1) 73 | //printf("Return %d %d %s\n", ret, errno, strerror(errno)); 74 | return ret; 75 | } 76 | 77 | static void encode_base_64(char *src, char *dest, int max_len) { 78 | static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 79 | int n, l, i; 80 | l = strlen(src); 81 | max_len = (max_len - 1) / 4; 82 | for(i = 0; i < max_len; i++, src += 3, l -= 3) { 83 | switch (l) { 84 | case 0: 85 | break; 86 | case 1: 87 | n = src[0] << 16; 88 | *dest++ = base64[(n >> 18) & 077]; 89 | *dest++ = base64[(n >> 12) & 077]; 90 | *dest++ = '='; 91 | *dest++ = '='; 92 | break; 93 | case 2: 94 | n = src[0] << 16 | src[1] << 8; 95 | *dest++ = base64[(n >> 18) & 077]; 96 | *dest++ = base64[(n >> 12) & 077]; 97 | *dest++ = base64[(n >> 6) & 077]; 98 | *dest++ = '='; 99 | break; 100 | default: 101 | n = src[0] << 16 | src[1] << 8 | src[2]; 102 | *dest++ = base64[(n >> 18) & 077]; 103 | *dest++ = base64[(n >> 12) & 077]; 104 | *dest++ = base64[(n >> 6) & 077]; 105 | *dest++ = base64[n & 077]; 106 | } 107 | if(l < 3) 108 | break; 109 | } 110 | *dest++ = 0; 111 | } 112 | 113 | void proxychains_write_log(char *str, ...) { 114 | char buff[1024*20]; 115 | va_list arglist; 116 | if(!proxychains_quiet_mode) { 117 | va_start(arglist, str); 118 | vsnprintf(buff, sizeof(buff), str, arglist); 119 | va_end(arglist); 120 | fprintf(stderr, "%s", buff); 121 | fflush(stderr); 122 | } 123 | } 124 | 125 | static int write_n_bytes(int fd, char *buff, size_t size) { 126 | int i = 0; 127 | size_t wrote = 0; 128 | for(;;) { 129 | i = write(fd, &buff[wrote], size - wrote); 130 | if(i <= 0) 131 | return i; 132 | wrote += i; 133 | if(wrote == size) 134 | return wrote; 135 | } 136 | } 137 | 138 | static int read_n_bytes(int fd, char *buff, size_t size) { 139 | int ready; 140 | size_t i; 141 | struct pollfd pfd[1]; 142 | 143 | pfd[0].fd = fd; 144 | pfd[0].events = POLLIN; 145 | for(i = 0; i < size; i++) { 146 | pfd[0].revents = 0; 147 | ready = poll_retry(pfd, 1, tcp_read_time_out); 148 | if(ready != 1 || !(pfd[0].revents & POLLIN) || 1 != read(fd, &buff[i], 1)) 149 | return -1; 150 | } 151 | return (int) size; 152 | } 153 | 154 | #ifdef ANDROID 155 | //shadowsocks-libev 156 | static int 157 | protect_socket(int fd) 158 | { 159 | int sock; 160 | struct sockaddr_un addr; 161 | 162 | if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 163 | proxychains_write_log(LOG_PREFIX "[EROOR][android] socket() failed: %s (socket fd = %d)\n", strerror(errno), sock); 164 | return -1; 165 | } 166 | 167 | // Set timeout to 1s 168 | struct timeval tv; 169 | tv.tv_sec = 1; 170 | tv.tv_usec = 0; 171 | setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); 172 | setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval)); 173 | 174 | char path[257]; 175 | sprintf(path, "%s/protect_path", getenv("PROXYCHAINS_PROTECT_FD_PREFIX")); 176 | 177 | memset(&addr, 0, sizeof(addr)); 178 | addr.sun_family = AF_UNIX; 179 | strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); 180 | 181 | if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { 182 | proxychains_write_log(LOG_PREFIX "[EROOR][android] connect() failed: %s (socket fd = %d), path: %s\n", 183 | strerror(errno), sock, path); 184 | close(sock); 185 | return -1; 186 | } 187 | 188 | if (ancil_send_fd(sock, fd)) { 189 | perror("[android] ancil_send_fd"); 190 | close(sock); 191 | return -1; 192 | } 193 | 194 | char ret = 0; 195 | 196 | if (recv(sock, &ret, 1, 0) == -1) { 197 | perror("[android] recv"); 198 | close(sock); 199 | return -1; 200 | } 201 | 202 | close(sock); 203 | return ret; 204 | } 205 | #endif 206 | 207 | static int timed_connect(int sock, const struct sockaddr *addr, socklen_t len) { 208 | int ret, value; 209 | socklen_t value_len; 210 | struct pollfd pfd[1]; 211 | PFUNC(); 212 | 213 | pfd[0].fd = sock; 214 | pfd[0].events = POLLOUT; 215 | fcntl(sock, F_SETFL, O_NONBLOCK); 216 | 217 | #ifdef ANDROID 218 | if (getenv("PROXYCHAINS_PROTECT_FD_PREFIX")) { 219 | protect_socket(pfd[0].fd); 220 | } 221 | #endif 222 | 223 | ret = true_connect(sock, addr, len); 224 | PDEBUG("\nconnect ret=%d\n", ret); 225 | 226 | if(ret == -1 && errno == EINPROGRESS) { 227 | ret = poll_retry(pfd, 1, tcp_connect_time_out); 228 | PDEBUG("\npoll ret=%d\n", ret); 229 | if(ret == 1) { 230 | value_len = sizeof(socklen_t); 231 | getsockopt(sock, SOL_SOCKET, SO_ERROR, &value, &value_len); 232 | PDEBUG("\nvalue=%d\n", value); 233 | if(!value) 234 | ret = 0; 235 | else 236 | ret = -1; 237 | } else { 238 | ret = -1; 239 | } 240 | } else { 241 | #ifdef DEBUG 242 | if(ret == -1) 243 | perror("true_connect"); 244 | #endif 245 | if(ret != 0) 246 | ret = -1; 247 | } 248 | 249 | fcntl(sock, F_SETFL, !O_NONBLOCK); 250 | return ret; 251 | } 252 | 253 | 254 | #define INVALID_INDEX 0xFFFFFFFFU 255 | static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, char *user, char *pass) { 256 | char *dns_name = NULL; 257 | char hostnamebuf[MSG_LEN_MAX]; 258 | size_t dns_len = 0; 259 | 260 | PFUNC(); 261 | 262 | // we use ip addresses with 224.* to lookup their dns name in our table, to allow remote DNS resolution 263 | // the range 224-255.* is reserved, and it won't go outside (unless the app does some other stuff with 264 | // the results returned from gethostbyname et al.) 265 | // the hardcoded number 224 can now be changed using the config option remote_dns_subnet to i.e. 127 266 | if(!ip.is_v6 && ip.addr.v4.octet[0] == remote_dns_subnet) { 267 | dns_len = at_get_host_for_ip(ip.addr.v4, hostnamebuf); 268 | if(!dns_len) goto err; 269 | else dns_name = hostnamebuf; 270 | } 271 | 272 | PDEBUG("host dns %s\n", dns_name ? dns_name : ""); 273 | 274 | size_t ulen = strlen(user); 275 | size_t passlen = strlen(pass); 276 | 277 | if(ulen > 0xFF || passlen > 0xFF || dns_len > 0xFF) { 278 | proxychains_write_log(LOG_PREFIX "error: maximum size of 255 for user/pass or domain name!\n"); 279 | goto err; 280 | } 281 | 282 | int len; 283 | unsigned char buff[BUFF_SIZE]; 284 | char ip_buf[INET6_ADDRSTRLEN]; 285 | int v6 = ip.is_v6; 286 | 287 | switch (pt) { 288 | case HTTP_TYPE:{ 289 | if(!dns_len) { 290 | if(!inet_ntop(v6?AF_INET6:AF_INET,ip.addr.v6,ip_buf,sizeof ip_buf)) { 291 | proxychains_write_log(LOG_PREFIX "error: ip address conversion failed\n"); 292 | goto err; 293 | } 294 | dns_name = ip_buf; 295 | } 296 | #define HTTP_AUTH_MAX ((0xFF * 2) + 1 + 1) /* 2 * 0xff: username and pass, plus 1 for ':' and 1 for zero terminator. */ 297 | char src[HTTP_AUTH_MAX]; 298 | char dst[(4 * HTTP_AUTH_MAX)]; 299 | if(ulen) { 300 | snprintf(src, sizeof(src), "%s:%s", user, pass); 301 | encode_base_64(src, dst, sizeof(dst)); 302 | } else dst[0] = 0; 303 | 304 | uint16_t hs_port = ntohs(port); 305 | len = snprintf((char *) buff, sizeof(buff), 306 | "CONNECT %s:%d HTTP/1.0\r\nHost: %s:%d\r\n%s%s%s\r\n", 307 | dns_name, hs_port, 308 | dns_name, hs_port, 309 | ulen ? "Proxy-Authorization: Basic " : dst, 310 | dst, ulen ? "\r\n" : dst); 311 | 312 | if(len < 0 || len != send(sock, buff, len, 0)) 313 | goto err; 314 | 315 | len = 0; 316 | // read header byte by byte. 317 | while(len < BUFF_SIZE) { 318 | if(1 == read_n_bytes(sock, (char *) (buff + len), 1)) 319 | len++; 320 | else 321 | goto err; 322 | if(len > 4 && 323 | buff[len - 1] == '\n' && 324 | buff[len - 2] == '\r' && buff[len - 3] == '\n' && buff[len - 4] == '\r') 325 | break; 326 | } 327 | 328 | // if not ok (200) or response greather than BUFF_SIZE return BLOCKED; 329 | if(len == BUFF_SIZE || !(buff[9] == '2' && buff[10] == '0' && buff[11] == '0')) { 330 | PDEBUG("HTTP proxy blocked: buff=\"%s\"\n", buff); 331 | return BLOCKED; 332 | } 333 | 334 | return SUCCESS; 335 | } 336 | break; 337 | case SOCKS4_TYPE:{ 338 | if(v6) { 339 | proxychains_write_log(LOG_PREFIX "error: SOCKS4 doesn't support ipv6 addresses\n"); 340 | goto err; 341 | } 342 | buff[0] = 4; // socks version 343 | buff[1] = 1; // connect command 344 | memcpy(&buff[2], &port, 2); // dest port 345 | if(dns_len) { 346 | ip.addr.v4.octet[0] = 0; 347 | ip.addr.v4.octet[1] = 0; 348 | ip.addr.v4.octet[2] = 0; 349 | ip.addr.v4.octet[3] = 1; 350 | } 351 | memcpy(&buff[4], &ip.addr.v4, 4); // dest host 352 | len = ulen + 1; // username 353 | if(len > 1) 354 | memcpy(&buff[8], user, len); 355 | else { 356 | buff[8] = 0; 357 | } 358 | 359 | // do socksv4a dns resolution on the server 360 | if(dns_len) { 361 | memcpy(&buff[8 + len], dns_name, dns_len + 1); 362 | len += dns_len + 1; 363 | } 364 | 365 | if((len + 8) != write_n_bytes(sock, (char *) buff, (8 + len))) 366 | goto err; 367 | 368 | if(8 != read_n_bytes(sock, (char *) buff, 8)) 369 | goto err; 370 | 371 | if(buff[0] != 0 || buff[1] != 90) 372 | return BLOCKED; 373 | 374 | return SUCCESS; 375 | } 376 | break; 377 | case SOCKS5_TYPE:{ 378 | int n_methods = ulen ? 2 : 1; 379 | buff[0] = 5; // version 380 | buff[1] = n_methods ; // number of methods 381 | buff[2] = 0; // no auth method 382 | if(ulen) buff[3] = 2; /// auth method -> username / password 383 | if(2+n_methods != write_n_bytes(sock, (char *) buff, 2+n_methods)) 384 | goto err; 385 | 386 | if(2 != read_n_bytes(sock, (char *) buff, 2)) 387 | goto err; 388 | 389 | if(buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) { 390 | if(buff[0] == 5 && buff[1] == 0xFF) 391 | return BLOCKED; 392 | else 393 | goto err; 394 | } 395 | 396 | if(buff[1] == 2) { 397 | // authentication 398 | char in[2]; 399 | char out[515]; 400 | char *cur = out; 401 | size_t c; 402 | *cur++ = 1; // version 403 | c = ulen & 0xFF; 404 | *cur++ = c; 405 | memcpy(cur, user, c); 406 | cur += c; 407 | c = passlen & 0xFF; 408 | *cur++ = c; 409 | memcpy(cur, pass, c); 410 | cur += c; 411 | 412 | if((cur - out) != write_n_bytes(sock, out, cur - out)) 413 | goto err; 414 | 415 | 416 | if(2 != read_n_bytes(sock, in, 2)) 417 | goto err; 418 | if(in[0] != 1 || in[1] != 0) { 419 | if(in[0] != 1) 420 | goto err; 421 | else 422 | return BLOCKED; 423 | } 424 | } 425 | int buff_iter = 0; 426 | buff[buff_iter++] = 5; // version 427 | buff[buff_iter++] = 1; // connect 428 | buff[buff_iter++] = 0; // reserved 429 | 430 | if(!dns_len) { 431 | buff[buff_iter++] = v6 ? 4 : 1; // ip v4/v6 432 | memcpy(buff + buff_iter, ip.addr.v6, v6?16:4); // dest host 433 | buff_iter += v6?16:4; 434 | } else { 435 | buff[buff_iter++] = 3; //dns 436 | buff[buff_iter++] = dns_len & 0xFF; 437 | memcpy(buff + buff_iter, dns_name, dns_len); 438 | buff_iter += dns_len; 439 | } 440 | 441 | memcpy(buff + buff_iter, &port, 2); // dest port 442 | buff_iter += 2; 443 | 444 | 445 | if(buff_iter != write_n_bytes(sock, (char *) buff, buff_iter)) 446 | goto err; 447 | 448 | if(4 != read_n_bytes(sock, (char *) buff, 4)) 449 | goto err; 450 | 451 | if(buff[0] != 5 || buff[1] != 0) 452 | goto err; 453 | 454 | switch (buff[3]) { 455 | case 1: 456 | len = 4; 457 | break; 458 | case 4: 459 | len = 16; 460 | break; 461 | case 3: 462 | len = 0; 463 | if(1 != read_n_bytes(sock, (char *) &len, 1)) 464 | goto err; 465 | break; 466 | default: 467 | goto err; 468 | } 469 | 470 | if(len + 2 != read_n_bytes(sock, (char *) buff, len + 2)) 471 | goto err; 472 | 473 | return SUCCESS; 474 | } 475 | break; 476 | } 477 | 478 | err: 479 | return SOCKET_ERROR; 480 | } 481 | 482 | #define TP " ... " 483 | #define DT "Dynamic chain" 484 | #define ST "Strict chain" 485 | #define RT "Random chain" 486 | #define RRT "Round Robin chain" 487 | 488 | static int start_chain(int *fd, proxy_data * pd, char *begin_mark) { 489 | int v6 = pd->ip.is_v6; 490 | 491 | *fd = socket(v6?PF_INET6:PF_INET, SOCK_STREAM, 0); 492 | if(*fd == -1) 493 | goto error; 494 | 495 | char ip_buf[INET6_ADDRSTRLEN]; 496 | if(!inet_ntop(v6?AF_INET6:AF_INET,pd->ip.addr.v6,ip_buf,sizeof ip_buf)) 497 | goto error; 498 | 499 | proxychains_write_log(LOG_PREFIX "%s " TP " %s:%d ", 500 | begin_mark, ip_buf, htons(pd->port)); 501 | pd->ps = PLAY_STATE; 502 | struct sockaddr_in addr = { 503 | .sin_family = AF_INET, 504 | .sin_port = pd->port, 505 | .sin_addr.s_addr = (in_addr_t) pd->ip.addr.v4.as_int 506 | }; 507 | struct sockaddr_in6 addr6 = { 508 | .sin6_family = AF_INET6, 509 | .sin6_port = pd->port, 510 | }; 511 | if(v6) memcpy(&addr6.sin6_addr.s6_addr, pd->ip.addr.v6, 16); 512 | if(timed_connect(*fd, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr))) { 513 | pd->ps = DOWN_STATE; 514 | goto error1; 515 | } 516 | pd->ps = BUSY_STATE; 517 | return SUCCESS; 518 | error1: 519 | proxychains_write_log(TP " timeout\n"); 520 | error: 521 | if(*fd != -1) 522 | close(*fd); 523 | return SOCKET_ERROR; 524 | } 525 | 526 | static proxy_data *select_proxy(select_type how, proxy_data * pd, unsigned int proxy_count, unsigned int *offset) { 527 | unsigned int i = 0, k = 0; 528 | if(*offset >= proxy_count) 529 | return NULL; 530 | switch (how) { 531 | case RANDOMLY: 532 | do { 533 | k++; 534 | i = rand() % proxy_count; 535 | } while(pd[i].ps != PLAY_STATE && k < proxy_count * 100); 536 | break; 537 | case FIFOLY: 538 | for(i = *offset; i < proxy_count; i++) { 539 | if(pd[i].ps == PLAY_STATE) { 540 | *offset = i; 541 | break; 542 | } 543 | } 544 | default: 545 | break; 546 | } 547 | if(i >= proxy_count) 548 | i = 0; 549 | return (pd[i].ps == PLAY_STATE) ? &pd[i] : NULL; 550 | } 551 | 552 | 553 | static void release_all(proxy_data * pd, unsigned int proxy_count) { 554 | unsigned int i; 555 | for(i = 0; i < proxy_count; i++) 556 | pd[i].ps = PLAY_STATE; 557 | return; 558 | } 559 | 560 | static void release_busy(proxy_data * pd, unsigned int proxy_count) { 561 | unsigned int i; 562 | for(i = 0; i < proxy_count; i++) 563 | if(pd[i].ps == BUSY_STATE) 564 | pd[i].ps = PLAY_STATE; 565 | return; 566 | } 567 | 568 | static unsigned int calc_alive(proxy_data * pd, unsigned int proxy_count) { 569 | unsigned int i; 570 | int alive_count = 0; 571 | release_busy(pd, proxy_count); 572 | for(i = 0; i < proxy_count; i++) 573 | if(pd[i].ps == PLAY_STATE) 574 | alive_count++; 575 | return alive_count; 576 | } 577 | 578 | 579 | static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) { 580 | int retcode = -1; 581 | char *hostname; 582 | char hostname_buf[MSG_LEN_MAX]; 583 | char ip_buf[INET6_ADDRSTRLEN]; 584 | int v6 = pto->ip.is_v6; 585 | 586 | PFUNC(); 587 | 588 | if(!v6 && pto->ip.addr.v4.octet[0] == remote_dns_subnet) { 589 | if(!at_get_host_for_ip(pto->ip.addr.v4, hostname_buf)) goto usenumericip; 590 | else hostname = hostname_buf; 591 | } else { 592 | usenumericip: 593 | if(!inet_ntop(v6?AF_INET6:AF_INET,pto->ip.addr.v6,ip_buf,sizeof ip_buf)) { 594 | pto->ps = DOWN_STATE; 595 | proxychains_write_log("<--ip conversion error!\n"); 596 | close(ns); 597 | return SOCKET_ERROR; 598 | } 599 | hostname = ip_buf; 600 | } 601 | 602 | proxychains_write_log(TP " %s:%d ", hostname, htons(pto->port)); 603 | retcode = tunnel_to(ns, pto->ip, pto->port, pfrom->pt, pfrom->user, pfrom->pass); 604 | switch (retcode) { 605 | case SUCCESS: 606 | pto->ps = BUSY_STATE; 607 | break; 608 | case BLOCKED: 609 | pto->ps = BLOCKED_STATE; 610 | proxychains_write_log("<--denied\n"); 611 | close(ns); 612 | break; 613 | case SOCKET_ERROR: 614 | pto->ps = DOWN_STATE; 615 | proxychains_write_log("<--socket error or timeout!\n"); 616 | close(ns); 617 | break; 618 | } 619 | return retcode; 620 | } 621 | 622 | int connect_proxy_chain(int sock, ip_type target_ip, 623 | unsigned short target_port, proxy_data * pd, 624 | unsigned int proxy_count, chain_type ct, unsigned int max_chain) { 625 | proxy_data p4; 626 | proxy_data *p1, *p2, *p3; 627 | int ns = -1; 628 | int rc = -1; 629 | unsigned int offset = 0; 630 | unsigned int alive_count = 0; 631 | unsigned int curr_len = 0; 632 | unsigned int curr_pos = 0; 633 | unsigned int looped = 0; // went back to start of list in RR mode 634 | 635 | p3 = &p4; 636 | 637 | PFUNC(); 638 | 639 | again: 640 | rc = -1; 641 | DUMP_PROXY_CHAIN(pd, proxy_count); 642 | 643 | switch (ct) { 644 | case DYNAMIC_TYPE: 645 | alive_count = calc_alive(pd, proxy_count); 646 | offset = 0; 647 | do { 648 | if(!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) 649 | goto error_more; 650 | } while(SUCCESS != start_chain(&ns, p1, DT) && offset < proxy_count); 651 | for(;;) { 652 | p2 = select_proxy(FIFOLY, pd, proxy_count, &offset); 653 | if(!p2) 654 | break; 655 | if(SUCCESS != chain_step(ns, p1, p2)) { 656 | PDEBUG("GOTO AGAIN 1\n"); 657 | goto again; 658 | } 659 | p1 = p2; 660 | } 661 | //proxychains_write_log(TP); 662 | p3->ip = target_ip; 663 | p3->port = target_port; 664 | if(SUCCESS != chain_step(ns, p1, p3)) 665 | goto error; 666 | break; 667 | 668 | case ROUND_ROBIN_TYPE: 669 | alive_count = calc_alive(pd, proxy_count); 670 | curr_pos = offset = proxychains_proxy_offset; 671 | if(alive_count < max_chain) 672 | goto error_more; 673 | PDEBUG("1:rr_offset = %d, curr_pos = %d\n", offset, curr_pos); 674 | /* Check from current RR offset til end */ 675 | for (;rc != SUCCESS;) { 676 | if (!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) { 677 | /* We've reached the end of the list, go to the start */ 678 | offset = 0; 679 | looped++; 680 | continue; 681 | } else if (looped && rc > 0 && offset >= curr_pos) { 682 | PDEBUG("GOTO MORE PROXIES 0\n"); 683 | /* We've gone back to the start and now past our starting position */ 684 | proxychains_proxy_offset = 0; 685 | goto error_more; 686 | } 687 | PDEBUG("2:rr_offset = %d\n", offset); 688 | rc=start_chain(&ns, p1, RRT); 689 | } 690 | /* Create rest of chain using RR */ 691 | for(curr_len = 1; curr_len < max_chain;) { 692 | PDEBUG("3:rr_offset = %d, curr_len = %d, max_chain = %d\n", offset, curr_len, max_chain); 693 | p2 = select_proxy(FIFOLY, pd, proxy_count, &offset); 694 | if(!p2) { 695 | /* Try from the beginning to where we started */ 696 | offset = 0; 697 | continue; 698 | } else if(SUCCESS != chain_step(ns, p1, p2)) { 699 | PDEBUG("GOTO AGAIN 1\n"); 700 | goto again; 701 | } else 702 | p1 = p2; 703 | curr_len++; 704 | } 705 | //proxychains_write_log(TP); 706 | p3->ip = target_ip; 707 | p3->port = target_port; 708 | proxychains_proxy_offset = offset+1; 709 | PDEBUG("pd_offset = %d, curr_len = %d\n", proxychains_proxy_offset, curr_len); 710 | if(SUCCESS != chain_step(ns, p1, p3)) 711 | goto error; 712 | break; 713 | 714 | case STRICT_TYPE: 715 | alive_count = calc_alive(pd, proxy_count); 716 | offset = 0; 717 | if(!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) { 718 | PDEBUG("select_proxy failed\n"); 719 | goto error_strict; 720 | } 721 | if(SUCCESS != start_chain(&ns, p1, ST)) { 722 | PDEBUG("start_chain failed\n"); 723 | goto error_strict; 724 | } 725 | while(offset < proxy_count) { 726 | if(!(p2 = select_proxy(FIFOLY, pd, proxy_count, &offset))) 727 | break; 728 | if(SUCCESS != chain_step(ns, p1, p2)) { 729 | PDEBUG("chain_step failed\n"); 730 | goto error_strict; 731 | } 732 | p1 = p2; 733 | } 734 | //proxychains_write_log(TP); 735 | p3->ip = target_ip; 736 | p3->port = target_port; 737 | if(SUCCESS != chain_step(ns, p1, p3)) 738 | goto error; 739 | break; 740 | 741 | case RANDOM_TYPE: 742 | alive_count = calc_alive(pd, proxy_count); 743 | if(alive_count < max_chain) 744 | goto error_more; 745 | curr_len = offset = 0; 746 | do { 747 | if(!(p1 = select_proxy(RANDOMLY, pd, proxy_count, &offset))) 748 | goto error_more; 749 | } while(SUCCESS != start_chain(&ns, p1, RT) && offset < max_chain); 750 | while(++curr_len < max_chain) { 751 | if(!(p2 = select_proxy(RANDOMLY, pd, proxy_count, &offset))) 752 | goto error_more; 753 | if(SUCCESS != chain_step(ns, p1, p2)) { 754 | PDEBUG("GOTO AGAIN 2\n"); 755 | goto again; 756 | } 757 | p1 = p2; 758 | } 759 | //proxychains_write_log(TP); 760 | p3->ip = target_ip; 761 | p3->port = target_port; 762 | if(SUCCESS != chain_step(ns, p1, p3)) 763 | goto error; 764 | 765 | } 766 | 767 | proxychains_write_log(TP " OK\n"); 768 | dup2(ns, sock); 769 | close(ns); 770 | return 0; 771 | error: 772 | if(ns != -1) 773 | close(ns); 774 | errno = ECONNREFUSED; // for nmap ;) 775 | return -1; 776 | 777 | error_more: 778 | proxychains_write_log("\n!!!need more proxies!!!\n"); 779 | error_strict: 780 | PDEBUG("error\n"); 781 | 782 | release_all(pd, proxy_count); 783 | if(ns != -1) 784 | close(ns); 785 | errno = ETIMEDOUT; 786 | return -1; 787 | } 788 | 789 | void core_initialize(void) { 790 | } 791 | 792 | void core_unload(void) { 793 | } 794 | 795 | static void gethostbyname_data_setstring(struct gethostbyname_data* data, char* name) { 796 | snprintf(data->addr_name, sizeof(data->addr_name), "%s", name); 797 | data->hostent_space.h_name = data->addr_name; 798 | } 799 | 800 | extern ip_type4 hostsreader_get_numeric_ip_for_name(const char* name); 801 | struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* data) { 802 | PFUNC(); 803 | char buff[256]; 804 | 805 | data->resolved_addr_p[0] = (char *) &data->resolved_addr; 806 | data->resolved_addr_p[1] = NULL; 807 | 808 | data->hostent_space.h_addr_list = data->resolved_addr_p; 809 | // let aliases point to the NULL member, mimicking an empty list. 810 | data->hostent_space.h_aliases = &data->resolved_addr_p[1]; 811 | 812 | data->resolved_addr = 0; 813 | data->hostent_space.h_addrtype = AF_INET; 814 | data->hostent_space.h_length = sizeof(in_addr_t); 815 | 816 | gethostname(buff, sizeof(buff)); 817 | 818 | if(!strcmp(buff, name)) { 819 | data->resolved_addr = inet_addr(buff); 820 | if(data->resolved_addr == (in_addr_t) (-1)) 821 | data->resolved_addr = (in_addr_t) (ip_type_localhost.addr.v4.as_int); 822 | goto retname; 823 | } 824 | 825 | // this iterates over the "known hosts" db, usually /etc/hosts 826 | ip_type4 hdb_res = hostsreader_get_numeric_ip_for_name(name); 827 | if(hdb_res.as_int != ip_type_invalid.addr.v4.as_int) { 828 | data->resolved_addr = hdb_res.as_int; 829 | goto retname; 830 | } 831 | 832 | data->resolved_addr = at_get_ip_for_host((char*) name, strlen(name)).as_int; 833 | if(data->resolved_addr == (in_addr_t) ip_type_invalid.addr.v4.as_int) return NULL; 834 | 835 | retname: 836 | 837 | gethostbyname_data_setstring(data, (char*) name); 838 | 839 | PDEBUG("return hostent space\n"); 840 | 841 | return &data->hostent_space; 842 | } 843 | 844 | struct addrinfo_data { 845 | struct addrinfo addrinfo_space; 846 | struct sockaddr sockaddr_space; 847 | char addr_name[256]; 848 | }; 849 | 850 | void proxy_freeaddrinfo(struct addrinfo *res) { 851 | PFUNC(); 852 | free(res); 853 | } 854 | 855 | #if defined(IS_MAC) || defined(IS_OPENBSD) || defined(ANDROID) 856 | #ifdef IS_OPENBSD /* OpenBSD has its own incompatible getservbyname_r */ 857 | #define getservbyname_r mygetservbyname_r 858 | #endif 859 | /* getservbyname on mac is using thread local storage, so we dont need mutex 860 | TODO: check if the same applies to OpenBSD */ 861 | static int getservbyname_r(const char* name, const char* proto, struct servent* result_buf, 862 | char* buf, size_t buflen, struct servent** result) { 863 | PFUNC(); 864 | struct servent *res; 865 | int ret; 866 | (void) buf; (void) buflen; 867 | res = getservbyname(name, proto); 868 | if(res) { 869 | *result_buf = *res; 870 | *result = result_buf; 871 | ret = 0; 872 | } else { 873 | *result = NULL; 874 | ret = ENOENT; 875 | } 876 | return ret; 877 | } 878 | #endif 879 | 880 | int proxy_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { 881 | struct gethostbyname_data ghdata; 882 | struct addrinfo_data *space; 883 | struct servent *se = NULL; 884 | struct hostent *hp = NULL; 885 | struct servent se_buf; 886 | struct addrinfo *p; 887 | char buf[1024]; 888 | int port; 889 | PFUNC(); 890 | 891 | // printf("proxy_getaddrinfo node %s service %s\n",node,service); 892 | space = calloc(1, sizeof(struct addrinfo_data)); 893 | if(!space) goto err1; 894 | 895 | if(node && !inet_aton(node, &((struct sockaddr_in *) &space->sockaddr_space)->sin_addr)) { 896 | /* some folks (nmap) use getaddrinfo() with AI_NUMERICHOST to check whether a string 897 | containing a numeric ip was passed. we must return failure in that case. */ 898 | if(hints && (hints->ai_flags & AI_NUMERICHOST)) return EAI_NONAME; 899 | hp = proxy_gethostbyname(node, &ghdata); 900 | if(hp) 901 | memcpy(&((struct sockaddr_in *) &space->sockaddr_space)->sin_addr, 902 | *(hp->h_addr_list), sizeof(in_addr_t)); 903 | else 904 | goto err2; 905 | } 906 | if(service) getservbyname_r(service, NULL, &se_buf, buf, sizeof(buf), &se); 907 | 908 | port = se ? se->s_port : htons(atoi(service ? service : "0")); 909 | ((struct sockaddr_in *) &space->sockaddr_space)->sin_port = port; 910 | 911 | *res = p = &space->addrinfo_space; 912 | assert((size_t)p == (size_t) space); 913 | 914 | p->ai_addr = &space->sockaddr_space; 915 | if(node) 916 | snprintf(space->addr_name, sizeof(space->addr_name), "%s", node); 917 | p->ai_canonname = space->addr_name; 918 | p->ai_next = NULL; 919 | p->ai_family = space->sockaddr_space.sa_family = AF_INET; 920 | p->ai_addrlen = sizeof(space->sockaddr_space); 921 | 922 | if(hints) { 923 | p->ai_socktype = hints->ai_socktype; 924 | p->ai_flags = hints->ai_flags; 925 | p->ai_protocol = hints->ai_protocol; 926 | } else { 927 | #ifndef AI_V4MAPPED 928 | #define AI_V4MAPPED 0 929 | #endif 930 | p->ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG); 931 | } 932 | 933 | goto out; 934 | err2: 935 | free(space); 936 | err1: 937 | return 1; 938 | out: 939 | return 0; 940 | } 941 | -------------------------------------------------------------------------------- /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 BUFF_SIZE 8*1024 // used to read responses from proxies. 27 | #define MAX_LOCALNET 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 | } proxy_type; 46 | 47 | typedef enum { 48 | DYNAMIC_TYPE, 49 | STRICT_TYPE, 50 | RANDOM_TYPE, 51 | ROUND_ROBIN_TYPE 52 | } chain_type; 53 | 54 | typedef enum { 55 | PLAY_STATE, 56 | DOWN_STATE, 57 | BLOCKED_STATE, 58 | BUSY_STATE 59 | } proxy_state; 60 | 61 | typedef enum { 62 | RANDOMLY, 63 | FIFOLY 64 | } select_type; 65 | 66 | typedef struct { 67 | struct in_addr in_addr, netmask; 68 | unsigned short port; 69 | } localaddr_arg; 70 | 71 | typedef struct { 72 | ip_type ip; 73 | unsigned short port; 74 | proxy_type pt; 75 | proxy_state ps; 76 | char user[256]; 77 | char pass[256]; 78 | } proxy_data; 79 | 80 | int connect_proxy_chain (int sock, ip_type target_ip, unsigned short target_port, 81 | proxy_data * pd, unsigned int proxy_count, chain_type ct, 82 | unsigned int max_chain ); 83 | 84 | void proxychains_write_log(char *str, ...); 85 | 86 | typedef int (*close_t)(int); 87 | typedef int (*connect_t)(int, const struct sockaddr *, socklen_t); 88 | typedef struct hostent* (*gethostbyname_t)(const char *); 89 | typedef int (*freeaddrinfo_t)(struct addrinfo *); 90 | typedef struct hostent *(*gethostbyaddr_t) (const void *, socklen_t, int); 91 | 92 | typedef int (*getaddrinfo_t)(const char *, const char *, const struct addrinfo *, 93 | struct addrinfo **); 94 | 95 | typedef int (*getnameinfo_t) (const struct sockaddr *, socklen_t, char *, 96 | socklen_t, char *, socklen_t, int); 97 | 98 | typedef ssize_t (*sendto_t) (int sockfd, const void *buf, size_t len, int flags, 99 | const struct sockaddr *dest_addr, socklen_t addrlen); 100 | 101 | 102 | 103 | extern connect_t true_connect; 104 | extern gethostbyname_t true_gethostbyname; 105 | extern getaddrinfo_t true_getaddrinfo; 106 | extern freeaddrinfo_t true_freeaddrinfo; 107 | extern getnameinfo_t true_getnameinfo; 108 | extern gethostbyaddr_t true_gethostbyaddr; 109 | 110 | struct gethostbyname_data { 111 | struct hostent hostent_space; 112 | in_addr_t resolved_addr; 113 | char *resolved_addr_p[2]; 114 | char addr_name[1024 * 8]; 115 | }; 116 | 117 | struct hostent* proxy_gethostbyname(const char *name, struct gethostbyname_data *data); 118 | 119 | int proxy_getaddrinfo(const char *node, const char *service, 120 | const struct addrinfo *hints, struct addrinfo **res); 121 | void proxy_freeaddrinfo(struct addrinfo *res); 122 | 123 | void core_initialize(void); 124 | void core_unload(void); 125 | 126 | #include "debug.h" 127 | 128 | #endif 129 | 130 | //RcB: DEP "core.c" 131 | //RcB: DEP "libproxychains.c" 132 | //RcB: LINK "-Wl,--no-as-needed -ldl -lpthread" 133 | -------------------------------------------------------------------------------- /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 | #ifdef DEBUG 5 | # include 6 | # define PSTDERR(fmt, args...) do { dprintf(2,fmt, ## args); } while(0) 7 | # define PDEBUG(fmt, args...) PSTDERR("DEBUG:"fmt, ## args) 8 | # define DEBUGDECL(args...) args 9 | 10 | # include "core.h" 11 | void DUMP_PROXY_CHAIN(proxy_data *pchain, unsigned int count); 12 | 13 | #else 14 | # define PDEBUG(fmt, args...) do {} while (0) 15 | # define DEBUGDECL(args...) 16 | # define DUMP_PROXY_CHAIN(args...) do {} while (0) 17 | #endif 18 | 19 | # define PFUNC() do { PDEBUG("pid[%d]:%s\n", getpid(), __FUNCTION__); } while(0) 20 | 21 | #endif 22 | 23 | -------------------------------------------------------------------------------- /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 | 5 | /* 6 | simple reader for /etc/hosts 7 | it only supports comments, blank lines and lines consisting of an ipv4 hostname pair. 8 | this is required so we can return entries from the host db without messing up the 9 | non-thread-safe state of libc's gethostent(). 10 | 11 | */ 12 | 13 | struct hostsreader { 14 | FILE *f; 15 | char* ip, *name; 16 | }; 17 | 18 | int hostsreader_open(struct hostsreader *ctx) { 19 | if(!(ctx->f = fopen("/etc/hosts", "r"))) return 0; 20 | return 1; 21 | } 22 | 23 | void hostsreader_close(struct hostsreader *ctx) { 24 | fclose(ctx->f); 25 | } 26 | 27 | static int isnumericipv4(const char* ipstring); 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(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 ip_type_invalid.addr.v4; 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 | 98 | /* isnumericipv4() taken from libulz */ 99 | static int isnumericipv4(const char* ipstring) { 100 | size_t x = 0, n = 0, d = 0; 101 | int wasdot = 0; 102 | while(1) { 103 | switch(ipstring[x]) { 104 | case 0: goto done; 105 | case '.': 106 | if(!n || wasdot) return 0; 107 | d++; 108 | wasdot = 1; 109 | break; 110 | case '0': case '1': case '2': case '3': case '4': 111 | case '5': case '6': case '7': case '8': case '9': 112 | n++; 113 | wasdot = 0; 114 | break; 115 | default: 116 | return 0; 117 | } 118 | x++; 119 | } 120 | done: 121 | if(d == 3 && n >= 4 && n <= 12) return 1; 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /src/ip_type.c: -------------------------------------------------------------------------------- 1 | #include "ip_type.h" 2 | 3 | const ip_type ip_type_invalid = { .addr.v4.as_int = -1 }; 4 | const ip_type ip_type_localhost = { .addr.v4.octet = {127, 0, 0, 1} }; 5 | 6 | -------------------------------------------------------------------------------- /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 | extern const ip_type ip_type_invalid; 20 | extern const ip_type ip_type_localhost; 21 | 22 | //RcB: DEP "ip_type.c" 23 | #endif 24 | -------------------------------------------------------------------------------- /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 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | 38 | #include "core.h" 39 | #include "common.h" 40 | 41 | #define satosin(x) ((struct sockaddr_in *) &(x)) 42 | #define SOCKADDR(x) (satosin(x)->sin_addr.s_addr) 43 | #define SOCKADDR_2(x) (satosin(x)->sin_addr) 44 | #define SOCKPORT(x) (satosin(x)->sin_port) 45 | #define SOCKFAMILY(x) (satosin(x)->sin_family) 46 | #define MAX_CHAIN 512 47 | 48 | close_t true_close; 49 | connect_t true_connect; 50 | gethostbyname_t true_gethostbyname; 51 | getaddrinfo_t true_getaddrinfo; 52 | freeaddrinfo_t true_freeaddrinfo; 53 | getnameinfo_t true_getnameinfo; 54 | gethostbyaddr_t true_gethostbyaddr; 55 | sendto_t true_sendto; 56 | 57 | int tcp_read_time_out; 58 | int tcp_connect_time_out; 59 | chain_type proxychains_ct; 60 | proxy_data proxychains_pd[MAX_CHAIN]; 61 | unsigned int proxychains_proxy_count = 0; 62 | unsigned int proxychains_proxy_offset = 0; 63 | int proxychains_got_chain_data = 0; 64 | unsigned int proxychains_max_chain = 1; 65 | int proxychains_quiet_mode = 0; 66 | int proxychains_resolver = 0; 67 | localaddr_arg localnet_addr[MAX_LOCALNET]; 68 | size_t num_localnet_addr = 0; 69 | unsigned int remote_dns_subnet = 224; 70 | 71 | pthread_once_t init_once = PTHREAD_ONCE_INIT; 72 | 73 | static int init_l = 0; 74 | 75 | static inline void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_type * ct); 76 | 77 | static void* load_sym(char* symname, void* proxyfunc) { 78 | 79 | void *funcptr = dlsym(RTLD_NEXT, symname); 80 | 81 | if(!funcptr) { 82 | fprintf(stderr, "Cannot load symbol '%s' %s\n", symname, dlerror()); 83 | exit(1); 84 | } else { 85 | PDEBUG("loaded symbol '%s'" " real addr %p wrapped addr %p\n", symname, funcptr, proxyfunc); 86 | } 87 | if(funcptr == proxyfunc) { 88 | PDEBUG("circular reference detected, aborting!\n"); 89 | abort(); 90 | } 91 | return funcptr; 92 | } 93 | 94 | #define INIT() init_lib_wrapper(__FUNCTION__) 95 | 96 | #define SETUP_SYM(X) do { if (! true_ ## X ) true_ ## X = load_sym( # X, X ); } while(0) 97 | 98 | #include "allocator_thread.h" 99 | 100 | const char *proxychains_get_version(void); 101 | 102 | static void setup_hooks(void) { 103 | SETUP_SYM(connect); 104 | SETUP_SYM(sendto); 105 | SETUP_SYM(gethostbyname); 106 | SETUP_SYM(getaddrinfo); 107 | SETUP_SYM(freeaddrinfo); 108 | SETUP_SYM(gethostbyaddr); 109 | #ifndef ANDROID 110 | SETUP_SYM(getnameinfo); 111 | #endif 112 | SETUP_SYM(close); 113 | } 114 | 115 | static int close_fds[16]; 116 | static int close_fds_cnt = 0; 117 | 118 | static void do_init(void) { 119 | srand(time(NULL)); 120 | core_initialize(); 121 | at_init(); 122 | 123 | /* read the config file */ 124 | get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct); 125 | DUMP_PROXY_CHAIN(proxychains_pd, proxychains_proxy_count); 126 | 127 | proxychains_write_log(LOG_PREFIX "DLL init: proxychains-ng %s\n", proxychains_get_version()); 128 | 129 | setup_hooks(); 130 | 131 | while(close_fds_cnt) true_close(close_fds[--close_fds_cnt]); 132 | 133 | init_l = 1; 134 | } 135 | 136 | static void init_lib_wrapper(const char* caller) { 137 | #ifndef DEBUG 138 | (void) caller; 139 | #endif 140 | if(!init_l) PDEBUG("%s called from %s\n", __FUNCTION__, caller); 141 | pthread_once(&init_once, do_init); 142 | } 143 | 144 | /* if we use gcc >= 3, we can instruct the dynamic loader 145 | * to call init_lib at link time. otherwise it gets loaded 146 | * lazily, which has the disadvantage that there's a potential 147 | * race condition if 2 threads call it before init_l is set 148 | * and PTHREAD support was disabled */ 149 | #if __GNUC__ > 2 150 | __attribute__((constructor)) 151 | static void gcc_init(void) { 152 | INIT(); 153 | } 154 | #endif 155 | 156 | /* get configuration from config file */ 157 | static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_type * ct) { 158 | int count = 0, port_n = 0, list = 0; 159 | char buff[1024], type[1024], host[1024], user[1024]; 160 | char *env; 161 | char local_in_addr_port[32]; 162 | char local_in_addr[32], local_in_port[32], local_netmask[32]; 163 | FILE *file = NULL; 164 | 165 | if(proxychains_got_chain_data) 166 | return; 167 | 168 | //Some defaults 169 | tcp_read_time_out = 4 * 1000; 170 | tcp_connect_time_out = 10 * 1000; 171 | *ct = DYNAMIC_TYPE; 172 | 173 | env = get_config_path(getenv(PROXYCHAINS_CONF_FILE_ENV_VAR), buff, sizeof(buff)); 174 | if( ( file = fopen(env, "r") ) == NULL ) 175 | { 176 | perror("couldnt read configuration file"); 177 | exit(1); 178 | } 179 | 180 | env = getenv(PROXYCHAINS_QUIET_MODE_ENV_VAR); 181 | if(env && *env == '1') 182 | proxychains_quiet_mode = 1; 183 | 184 | while(fgets(buff, sizeof(buff), file)) { 185 | if(buff[0] != '\n' && buff[strspn(buff, " ")] != '#') { 186 | /* proxylist has to come last */ 187 | if(list) { 188 | if(count >= MAX_CHAIN) 189 | break; 190 | 191 | memset(&pd[count], 0, sizeof(proxy_data)); 192 | 193 | pd[count].ps = PLAY_STATE; 194 | port_n = 0; 195 | 196 | int ret = sscanf(buff, "%s %s %d %s %s", type, host, &port_n, pd[count].user, pd[count].pass); 197 | if(ret < 3 || ret == EOF) { 198 | inv: 199 | fprintf(stderr, "error: invalid item in proxylist section: %s", buff); 200 | exit(1); 201 | } 202 | 203 | memset(&pd[count].ip, 0, sizeof(pd[count].ip)); 204 | pd[count].ip.is_v6 = !!strchr(host, ':'); 205 | pd[count].port = htons((unsigned short) port_n); 206 | ip_type* host_ip = &pd[count].ip; 207 | if(1 != inet_pton(host_ip->is_v6 ? AF_INET6 : AF_INET, host, host_ip->addr.v6)) { 208 | fprintf(stderr, "proxy %s has invalid value or is not numeric\n", host); 209 | exit(1); 210 | } 211 | 212 | if(!strcmp(type, "http")) { 213 | pd[count].pt = HTTP_TYPE; 214 | } else if(!strcmp(type, "socks4")) { 215 | pd[count].pt = SOCKS4_TYPE; 216 | } else if(!strcmp(type, "socks5")) { 217 | pd[count].pt = SOCKS5_TYPE; 218 | } else 219 | goto inv; 220 | 221 | if(port_n) 222 | count++; 223 | } else { 224 | if(strstr(buff, "[ProxyList]")) { 225 | list = 1; 226 | } else if(strstr(buff, "random_chain")) { 227 | *ct = RANDOM_TYPE; 228 | } else if(strstr(buff, "strict_chain")) { 229 | *ct = STRICT_TYPE; 230 | } else if(strstr(buff, "dynamic_chain")) { 231 | *ct = DYNAMIC_TYPE; 232 | } else if(strstr(buff, "round_robin_chain")) { 233 | *ct = ROUND_ROBIN_TYPE; 234 | } else if(strstr(buff, "tcp_read_time_out")) { 235 | sscanf(buff, "%s %d", user, &tcp_read_time_out); 236 | } else if(strstr(buff, "tcp_connect_time_out")) { 237 | sscanf(buff, "%s %d", user, &tcp_connect_time_out); 238 | } else if(strstr(buff, "remote_dns_subnet")) { 239 | sscanf(buff, "%s %u", user, &remote_dns_subnet); 240 | if(remote_dns_subnet >= 256) { 241 | fprintf(stderr, 242 | "remote_dns_subnet: invalid value. requires a number between 0 and 255.\n"); 243 | exit(1); 244 | } 245 | } else if(strstr(buff, "localnet")) { 246 | if(sscanf(buff, "%s %21[^/]/%15s", user, local_in_addr_port, local_netmask) < 3) { 247 | fprintf(stderr, "localnet format error"); 248 | exit(1); 249 | } 250 | /* clean previously used buffer */ 251 | memset(local_in_port, 0, sizeof(local_in_port) / sizeof(local_in_port[0])); 252 | 253 | if(sscanf(local_in_addr_port, "%15[^:]:%5s", local_in_addr, local_in_port) < 2) { 254 | PDEBUG("added localnet: netaddr=%s, netmask=%s\n", 255 | local_in_addr, local_netmask); 256 | } else { 257 | PDEBUG("added localnet: netaddr=%s, port=%s, netmask=%s\n", 258 | local_in_addr, local_in_port, local_netmask); 259 | } 260 | if(num_localnet_addr < MAX_LOCALNET) { 261 | int error; 262 | error = 263 | inet_pton(AF_INET, local_in_addr, 264 | &localnet_addr[num_localnet_addr].in_addr); 265 | if(error <= 0) { 266 | fprintf(stderr, "localnet address error\n"); 267 | exit(1); 268 | } 269 | error = 270 | inet_pton(AF_INET, local_netmask, 271 | &localnet_addr[num_localnet_addr].netmask); 272 | if(error <= 0) { 273 | fprintf(stderr, "localnet netmask error\n"); 274 | exit(1); 275 | } 276 | if(local_in_port[0]) { 277 | localnet_addr[num_localnet_addr].port = 278 | (short) atoi(local_in_port); 279 | } else { 280 | localnet_addr[num_localnet_addr].port = 0; 281 | } 282 | ++num_localnet_addr; 283 | } else { 284 | fprintf(stderr, "# of localnet exceed %d.\n", MAX_LOCALNET); 285 | } 286 | } else if(strstr(buff, "chain_len")) { 287 | char *pc; 288 | int len; 289 | pc = strchr(buff, '='); 290 | if(!pc) { 291 | fprintf(stderr, "error: missing equals sign '=' in chain_len directive.\n"); 292 | exit(1); 293 | } 294 | len = atoi(++pc); 295 | proxychains_max_chain = (len ? len : 1); 296 | } else if(strstr(buff, "quiet_mode")) { 297 | proxychains_quiet_mode = 1; 298 | } else if(strstr(buff, "proxy_dns")) { 299 | proxychains_resolver = 1; 300 | } 301 | } 302 | } 303 | } 304 | #ifndef BROKEN_FCLOSE 305 | fclose(file); 306 | #endif 307 | if(!count) { 308 | fprintf(stderr, "error: no valid proxy found in config\n"); 309 | exit(1); 310 | } 311 | *proxy_count = count; 312 | proxychains_got_chain_data = 1; 313 | } 314 | 315 | /******* HOOK FUNCTIONS *******/ 316 | 317 | int close(int fd) { 318 | if(!init_l) { 319 | if(close_fds_cnt>=(sizeof close_fds/sizeof close_fds[0])) goto err; 320 | close_fds[close_fds_cnt++] = fd; 321 | errno = 0; 322 | return 0; 323 | } 324 | /* prevent rude programs (like ssh) from closing our pipes */ 325 | if(fd != req_pipefd[0] && fd != req_pipefd[1] && 326 | fd != resp_pipefd[0] && fd != resp_pipefd[1]) { 327 | return true_close(fd); 328 | } 329 | err: 330 | errno = EBADF; 331 | return -1; 332 | } 333 | static int is_v4inv6(const struct in6_addr *a) { 334 | return a->s6_addr32[0] == 0 && a->s6_addr32[1] == 0 && 335 | a->s6_addr16[4] == 0 && a->s6_addr16[5] == 0xffff; 336 | } 337 | int connect(int sock, const struct sockaddr *addr, socklen_t len) { 338 | INIT(); 339 | PFUNC(); 340 | 341 | int socktype = 0, flags = 0, ret = 0; 342 | socklen_t optlen = 0; 343 | ip_type dest_ip; 344 | DEBUGDECL(char str[256]); 345 | 346 | struct in_addr *p_addr_in; 347 | struct in6_addr *p_addr_in6; 348 | unsigned short port; 349 | size_t i; 350 | int remote_dns_connect = 0; 351 | optlen = sizeof(socktype); 352 | sa_family_t fam = SOCKFAMILY(*addr); 353 | getsockopt(sock, SOL_SOCKET, SO_TYPE, &socktype, &optlen); 354 | if(!((fam == AF_INET || fam == AF_INET6) && socktype == SOCK_STREAM)) 355 | return true_connect(sock, addr, len); 356 | 357 | int v6 = dest_ip.is_v6 = fam == AF_INET6; 358 | 359 | p_addr_in = &((struct sockaddr_in *) addr)->sin_addr; 360 | p_addr_in6 = &((struct sockaddr_in6 *) addr)->sin6_addr; 361 | port = !v6 ? ntohs(((struct sockaddr_in *) addr)->sin_port) 362 | : ntohs(((struct sockaddr_in6 *) addr)->sin6_port); 363 | struct in_addr v4inv6; 364 | if(v6 && is_v4inv6(p_addr_in6)) { 365 | memcpy(&v4inv6.s_addr, &p_addr_in6->s6_addr32[3], 4); 366 | v6 = dest_ip.is_v6 = 0; 367 | p_addr_in = &v4inv6; 368 | } 369 | 370 | // PDEBUG("localnet: %s; ", inet_ntop(AF_INET,&in_addr_localnet, str, sizeof(str))); 371 | // PDEBUG("netmask: %s; " , inet_ntop(AF_INET, &in_addr_netmask, str, sizeof(str))); 372 | PDEBUG("target: %s\n", inet_ntop(v6 ? AF_INET6 : AF_INET, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, str, sizeof(str))); 373 | PDEBUG("port: %d\n", port); 374 | 375 | // check if connect called from proxydns 376 | remote_dns_connect = !v6 && (ntohl(p_addr_in->s_addr) >> 24 == remote_dns_subnet); 377 | 378 | if (!v6) for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) { 379 | if((localnet_addr[i].in_addr.s_addr & localnet_addr[i].netmask.s_addr) 380 | == (p_addr_in->s_addr & localnet_addr[i].netmask.s_addr)) { 381 | if(!localnet_addr[i].port || localnet_addr[i].port == port) { 382 | PDEBUG("accessing localnet using true_connect\n"); 383 | return true_connect(sock, addr, len); 384 | } 385 | } 386 | } 387 | 388 | flags = fcntl(sock, F_GETFL, 0); 389 | if(flags & O_NONBLOCK) 390 | fcntl(sock, F_SETFL, !O_NONBLOCK); 391 | 392 | memcpy(dest_ip.addr.v6, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, v6?16:4); 393 | 394 | ret = connect_proxy_chain(sock, 395 | dest_ip, 396 | htons(port), 397 | proxychains_pd, proxychains_proxy_count, proxychains_ct, proxychains_max_chain); 398 | 399 | fcntl(sock, F_SETFL, flags); 400 | if(ret != SUCCESS) 401 | errno = ECONNREFUSED; 402 | return ret; 403 | } 404 | 405 | static struct gethostbyname_data ghbndata; 406 | struct hostent *gethostbyname(const char *name) { 407 | INIT(); 408 | PDEBUG("gethostbyname: %s\n", name); 409 | 410 | if(proxychains_resolver) 411 | return proxy_gethostbyname(name, &ghbndata); 412 | else 413 | return true_gethostbyname(name); 414 | 415 | return NULL; 416 | } 417 | 418 | int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { 419 | INIT(); 420 | PDEBUG("getaddrinfo: %s %s\n", node ? node : "null", service ? service : "null"); 421 | 422 | if(proxychains_resolver) 423 | return proxy_getaddrinfo(node, service, hints, res); 424 | else 425 | return true_getaddrinfo(node, service, hints, res); 426 | } 427 | 428 | void freeaddrinfo(struct addrinfo *res) { 429 | INIT(); 430 | PDEBUG("freeaddrinfo %p \n", (void *) res); 431 | 432 | if(!proxychains_resolver) 433 | true_freeaddrinfo(res); 434 | else 435 | proxy_freeaddrinfo(res); 436 | } 437 | 438 | int pc_getnameinfo(const struct sockaddr *sa, socklen_t salen, 439 | char *host, socklen_t hostlen, char *serv, 440 | socklen_t servlen, int flags) 441 | { 442 | INIT(); 443 | PFUNC(); 444 | 445 | if(!proxychains_resolver) { 446 | return true_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); 447 | } else { 448 | if(!salen || !(SOCKFAMILY(*sa) == AF_INET || SOCKFAMILY(*sa) == AF_INET6)) 449 | return EAI_FAMILY; 450 | int v6 = SOCKFAMILY(*sa) == AF_INET6; 451 | if(salen < (v6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in))) 452 | return EAI_FAMILY; 453 | if(hostlen) { 454 | unsigned char v4inv6buf[4]; 455 | const void *ip = v6 ? (void*)&((struct sockaddr_in6*)sa)->sin6_addr 456 | : (void*)&((struct sockaddr_in*)sa)->sin_addr; 457 | unsigned scopeid = 0; 458 | if(v6) { 459 | if(is_v4inv6(&((struct sockaddr_in6*)sa)->sin6_addr)) { 460 | memcpy(v4inv6buf, &((struct sockaddr_in6*)sa)->sin6_addr.s6_addr32[3], 4); 461 | ip = v4inv6buf; 462 | v6 = 0; 463 | } else 464 | scopeid = ((struct sockaddr_in6 *)sa)->sin6_scope_id; 465 | } 466 | if(!inet_ntop(v6?AF_INET6:AF_INET,ip,host,hostlen)) 467 | return EAI_OVERFLOW; 468 | if(scopeid) { 469 | size_t l = strlen(host); 470 | if(snprintf(host+l, hostlen-l, "%%%u", scopeid) >= hostlen-l) 471 | return EAI_OVERFLOW; 472 | } 473 | } 474 | if(servlen) { 475 | if(snprintf(serv, servlen, "%d", ntohs(SOCKPORT(*sa))) >= servlen) 476 | return EAI_OVERFLOW; 477 | } 478 | } 479 | return 0; 480 | } 481 | 482 | #ifdef ANDROID 483 | struct hostent *gethostbyaddr(const char *addr, int len, int type) { 484 | #else 485 | struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) { 486 | #endif 487 | INIT(); 488 | PDEBUG("TODO: proper gethostbyaddr hook\n"); 489 | 490 | static char buf[16]; 491 | static char ipv4[4]; 492 | static char *list[2]; 493 | static char *aliases[1]; 494 | static struct hostent he; 495 | 496 | if(!proxychains_resolver) 497 | return true_gethostbyaddr(addr, len, type); 498 | else { 499 | 500 | PDEBUG("len %u\n", len); 501 | if(len != 4) 502 | return NULL; 503 | he.h_name = buf; 504 | memcpy(ipv4, addr, 4); 505 | list[0] = ipv4; 506 | list[1] = NULL; 507 | he.h_addr_list = list; 508 | he.h_addrtype = AF_INET; 509 | aliases[0] = NULL; 510 | he.h_aliases = aliases; 511 | he.h_length = 4; 512 | pc_stringfromipv4((unsigned char *) addr, buf); 513 | return &he; 514 | } 515 | return NULL; 516 | } 517 | 518 | #ifndef MSG_FASTOPEN 519 | # define MSG_FASTOPEN 0x20000000 520 | #endif 521 | 522 | ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, 523 | const struct sockaddr *dest_addr, socklen_t addrlen) { 524 | INIT(); 525 | PFUNC(); 526 | if (flags & MSG_FASTOPEN) { 527 | if (!connect(sockfd, dest_addr, addrlen) && errno != EINPROGRESS) { 528 | return -1; 529 | } 530 | dest_addr = NULL; 531 | addrlen = 0; 532 | flags &= ~MSG_FASTOPEN; 533 | } 534 | return true_sendto(sockfd, buf, len, flags, dest_addr, addrlen); 535 | } 536 | -------------------------------------------------------------------------------- /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 | #undef _POSIX_C_SOURCE 11 | #define _POSIX_C_SOURCE 200809L 12 | #undef _XOPEN_SOURCE 13 | #define _XOPEN_SOURCE 700 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "common.h" 23 | 24 | static int usage(char **argv) { 25 | printf("\nUsage:\t%s -q -f config_file program_name [arguments]\n" 26 | "\t-q makes proxychains quiet - this overrides the config setting\n" 27 | "\t-f allows one to manually specify a configfile to use\n" 28 | "\tfor example : proxychains telnet somehost.com\n" "More help in README file\n\n", argv[0]); 29 | return EXIT_FAILURE; 30 | } 31 | 32 | static const char *dll_name = DLL_NAME; 33 | 34 | static char own_dir[256]; 35 | static const char *dll_dirs[] = { 36 | #ifndef SUPER_SECURE /* CVE-2015-3887 */ 37 | ".", 38 | #endif 39 | own_dir, 40 | LIB_DIR, 41 | "/lib", 42 | "/usr/lib", 43 | "/usr/local/lib", 44 | "/lib64", 45 | NULL 46 | }; 47 | 48 | static void set_own_dir(const char *argv0) { 49 | size_t l = strlen(argv0); 50 | while(l && argv0[l - 1] != '/') 51 | l--; 52 | if(l == 0) 53 | #ifdef SUPER_SECURE 54 | memcpy(own_dir, "/dev/null/", 11); 55 | #else 56 | memcpy(own_dir, ".", 2); 57 | #endif 58 | else { 59 | memcpy(own_dir, argv0, l - 1); 60 | own_dir[l] = 0; 61 | } 62 | } 63 | 64 | #define MAX_COMMANDLINE_FLAGS 2 65 | 66 | int main(int argc, char *argv[]) { 67 | char *path = NULL; 68 | char buf[256]; 69 | char pbuf[256]; 70 | int start_argv = 1; 71 | int quiet = 0; 72 | size_t i; 73 | const char *prefix = NULL; 74 | 75 | for(i = 0; i < MAX_COMMANDLINE_FLAGS; i++) { 76 | if(start_argv < argc && argv[start_argv][0] == '-') { 77 | if(argv[start_argv][1] == 'q') { 78 | quiet = 1; 79 | start_argv++; 80 | } else if(argv[start_argv][1] == 'f') { 81 | 82 | if(start_argv + 1 < argc) 83 | path = argv[start_argv + 1]; 84 | else 85 | return usage(argv); 86 | 87 | start_argv += 2; 88 | } 89 | } else 90 | break; 91 | } 92 | 93 | if(start_argv >= argc) 94 | return usage(argv); 95 | 96 | /* check if path of config file has not been passed via command line */ 97 | path = get_config_path(path, pbuf, sizeof(pbuf)); 98 | 99 | if(!quiet) 100 | fprintf(stderr, LOG_PREFIX "config file found: %s\n", path); 101 | 102 | /* Set PROXYCHAINS_CONF_FILE to get proxychains lib to use new config file. */ 103 | setenv(PROXYCHAINS_CONF_FILE_ENV_VAR, path, 1); 104 | 105 | if(quiet) 106 | setenv(PROXYCHAINS_QUIET_MODE_ENV_VAR, "1", 1); 107 | 108 | 109 | // search DLL 110 | 111 | set_own_dir(argv[0]); 112 | 113 | i = 0; 114 | 115 | while(dll_dirs[i]) { 116 | snprintf(buf, sizeof(buf), "%s/%s", dll_dirs[i], dll_name); 117 | if(access(buf, R_OK) != -1) { 118 | prefix = dll_dirs[i]; 119 | break; 120 | } 121 | i++; 122 | } 123 | 124 | if(!prefix) { 125 | fprintf(stderr, "couldnt locate %s\n", dll_name); 126 | return EXIT_FAILURE; 127 | } 128 | if(!quiet) 129 | fprintf(stderr, LOG_PREFIX "preloading %s/%s\n", prefix, dll_name); 130 | 131 | #ifdef IS_MAC 132 | putenv("DYLD_FORCE_FLAT_NAMESPACE=1"); 133 | #define LD_PRELOAD_ENV "DYLD_INSERT_LIBRARIES" 134 | #define LD_PRELOAD_SEP ":" 135 | #else 136 | #define LD_PRELOAD_ENV "LD_PRELOAD" 137 | /* all historic implementations of BSD and linux dynlinkers seem to support 138 | space as LD_PRELOAD separator, with colon added only recently. 139 | we use the old syntax for maximum compat */ 140 | #define LD_PRELOAD_SEP " " 141 | #endif 142 | char *old_val = getenv(LD_PRELOAD_ENV); 143 | snprintf(buf, sizeof(buf), LD_PRELOAD_ENV "=%s/%s%s%s", 144 | prefix, dll_name, 145 | /* append previous LD_PRELOAD content, if existent */ 146 | old_val ? LD_PRELOAD_SEP : "", 147 | old_val ? old_val : ""); 148 | putenv(buf); 149 | execvp(argv[start_argv], &argv[start_argv]); 150 | perror("proxychains can't load process...."); 151 | 152 | return EXIT_FAILURE; 153 | } 154 | -------------------------------------------------------------------------------- /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/nameinfo.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern int pc_getnameinfo(const void *sa, socklen_t salen, 4 | char *host, socklen_t hostlen, char *serv, 5 | socklen_t servlen, int flags); 6 | 7 | 8 | int getnameinfo(const void *sa, socklen_t salen, 9 | char *host, socklen_t hostlen, char *serv, 10 | socklen_t servlen, int flags) { 11 | return pc_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /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 | proxy_dns 53 | 54 | # set the class A subnet number to use for the internal remote DNS mapping 55 | # we use the reserved 224.x.x.x range by default, 56 | # if the proxified app does a DNS request, we will return an IP from that range. 57 | # on further accesses to this ip we will send the saved DNS name to the proxy. 58 | # in case some control-freak app checks the returned ip, and denies to 59 | # connect, you can use another subnet, e.g. 10.x.x.x or 127.x.x.x. 60 | # of course you should make sure that the proxified app does not need 61 | # *real* access to this subnet. 62 | # i.e. dont use the same subnet then in the localnet section 63 | #remote_dns_subnet 127 64 | #remote_dns_subnet 10 65 | remote_dns_subnet 224 66 | 67 | # Some timeouts in milliseconds 68 | tcp_read_time_out 15000 69 | tcp_connect_time_out 8000 70 | 71 | ### Examples for localnet exclusion 72 | ## localnet ranges will *not* use a proxy to connect. 73 | ## Exclude connections to 192.168.1.0/24 with port 80 74 | # localnet 192.168.1.0:80/255.255.255.0 75 | 76 | ## Exclude connections to 192.168.100.0/24 77 | # localnet 192.168.100.0/255.255.255.0 78 | 79 | ## Exclude connections to ANYwhere with port 80 80 | # localnet 0.0.0.0:80/0.0.0.0 81 | 82 | ## RFC5735 Loopback address range 83 | ## if you enable this, you have to make sure remote_dns_subnet is not 127 84 | ## you'll need to enable it if you want to use an application that 85 | ## connects to localhost. 86 | # localnet 127.0.0.0/255.0.0.0 87 | 88 | ## RFC1918 Private Address Ranges 89 | # localnet 10.0.0.0/255.0.0.0 90 | # localnet 172.16.0.0/255.240.0.0 91 | # localnet 192.168.0.0/255.255.0.0 92 | 93 | # ProxyList format 94 | # type ip port [user pass] 95 | # (values separated by 'tab' or 'blank') 96 | # 97 | # only numeric ipv4 addresses are valid 98 | # 99 | # 100 | # Examples: 101 | # 102 | # socks5 192.168.67.78 1080 lamer secret 103 | # http 192.168.89.3 8080 justu hidden 104 | # socks4 192.168.1.49 1080 105 | # http 192.168.39.93 8080 106 | # 107 | # 108 | # proxy types: http, socks4, socks5 109 | # ( auth types supported: "basic"-http "user/pass"-socks ) 110 | # 111 | [ProxyList] 112 | # add proxy here ... 113 | # meanwile 114 | # defaults set to "tor" 115 | socks4 127.0.0.1 9050 116 | 117 | -------------------------------------------------------------------------------- /src/proxyresolv: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This is a legacy script that uses "dig" to do DNS lookups via TCP. 3 | # it is not actively maintained since proxychains no longer depends 4 | # on it. i leave it here as a bonus. 5 | 6 | # DNS server used to resolve names 7 | DNS_SERVER=8.8.8.8 8 | 9 | 10 | if [ $# = 0 ] ; then 11 | echo " usage:" 12 | echo " proxyresolv " 13 | exit 14 | fi 15 | 16 | 17 | export LD_PRELOAD=libproxychains4.so 18 | dig $1 @$DNS_SERVER +tcp | awk '/A.?[0-9]+\.[0-9]+\.[0-9]/{print $5;}' 19 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | #define VERSION "4.12-git-3-g423d5fb" 2 | -------------------------------------------------------------------------------- /tests/test_getaddrinfo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #ifndef NI_MAXHOST 8 | #define NI_MAXHOST 1025 9 | #endif 10 | 11 | int main(void) { 12 | struct addrinfo *result; 13 | struct addrinfo *res; 14 | int error; 15 | 16 | /* resolve the domain name into a list of addresses */ 17 | error = getaddrinfo("www.example.com", NULL, NULL, &result); 18 | if (error != 0) 19 | { 20 | fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error)); 21 | return EXIT_FAILURE; 22 | } 23 | 24 | /* loop over all returned results and do inverse lookup */ 25 | for (res = result; res != NULL; res = res->ai_next) 26 | { 27 | char hostname[NI_MAXHOST] = ""; 28 | 29 | error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0); 30 | if (error != 0) 31 | { 32 | fprintf(stderr, "error in getnameinfo: %s\n", gai_strerror(error)); 33 | continue; 34 | } 35 | if (*hostname != '\0') 36 | printf("hostname: %s\n", hostname); 37 | } 38 | 39 | freeaddrinfo(result); 40 | return EXIT_SUCCESS; 41 | } 42 | -------------------------------------------------------------------------------- /tests/test_gethostent.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../src/common.h" 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 | return 0; 127 | } 128 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------