├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── buildci.yml │ ├── stale.yml │ └── super-linter.yml ├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── Makefile ├── README.md ├── TODO ├── completions └── zsh │ └── _proxychains4 ├── configure ├── dist ├── config.mak └── proxychains.conf ├── proxychains.lsm ├── src ├── common.c ├── common.h ├── core.c ├── core.h ├── libproxychains.c ├── main.c ├── proxychains ├── proxychains.conf └── proxyresolv └── tests └── test_getaddrinfo.c /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Run command 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Additional context** 24 | Add any other context about the problem here. 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/buildci.yml: -------------------------------------------------------------------------------- 1 | name: Makefile CI 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | build-linux-ubuntu: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | 15 | - name: configure 16 | run: ./configure 17 | 18 | - name: Build Proxychains 19 | run: make 20 | 21 | - name: Run Proxychains 22 | run: ./proxychains4 -v 23 | 24 | - name: Run tests 25 | run: ./src/proxychains -f dist/proxychains.conf on 26 | 27 | # - name: Run tests 28 | # run: ./src/proxychains -f dist/proxychains.conf curl -o /dev/null -v https://sme.sk 29 | 30 | # - name: Run tests 31 | # run: ./src/proxychains -f dist/proxychains.conf ping -c 1 sme.sk 32 | build-macos: 33 | runs-on: macos-latest 34 | steps: 35 | - uses: actions/checkout@v3 36 | 37 | - name: configure 38 | run: ./configure 39 | 40 | - name: Build Proxychains 41 | run: make 42 | 43 | - name: Run Proxychains 44 | run: ./proxychains4 -v 45 | 46 | - name: Run tests 47 | run: ./src/proxychains -f dist/proxychains.conf on 48 | 49 | # - name: Run tests 50 | # run: ./src/proxychains -f dist/proxychains.conf curl -o /dev/null -v https://sme.sk 51 | 52 | # - name: Run tests 53 | # run: ./src/proxychains -f dist/proxychains.conf ping -t 1 sme.sk 54 | 55 | 56 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | # This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time. 2 | # 3 | # You can adjust the behavior by modifying this file. 4 | # For more information, see: 5 | # https://github.com/actions/stale 6 | name: Mark stale issues and pull requests 7 | 8 | on: 9 | schedule: 10 | - cron: '24 3 * * *' 11 | 12 | jobs: 13 | stale: 14 | 15 | runs-on: ubuntu-latest 16 | permissions: 17 | issues: write 18 | pull-requests: write 19 | 20 | steps: 21 | - uses: actions/stale@v5 22 | with: 23 | days-before-stale: 90 24 | days-before-close: 120 25 | repo-token: ${{ secrets.GITHUB_TOKEN }} 26 | stale-issue-message: 'Stale issue message' 27 | stale-pr-message: 'Stale pull request message' 28 | stale-issue-label: 'no-issue-activity' 29 | exempt-issue-labels: 'docu,roadmap,bug,possible-feature' 30 | stale-pr-label: 'no-pr-activity' 31 | exempt-pr-labels: 'feature' 32 | -------------------------------------------------------------------------------- /.github/workflows/super-linter.yml: -------------------------------------------------------------------------------- 1 | # This workflow executes several linters on changed files based on languages used in your code base whenever 2 | # you push a code or open a pull request. 3 | # 4 | # You can adjust the behavior by modifying this file. 5 | # For more information, see: 6 | # https://github.com/github/super-linter 7 | name: Lint Code Base 8 | 9 | on: 10 | push: 11 | branches: [ "master" ] 12 | pull_request: 13 | branches: [ "master" ] 14 | jobs: 15 | run-lint: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout code 19 | uses: actions/checkout@v3 20 | with: 21 | # Full git history is needed to get a proper list of changed files within `super-linter` 22 | fetch-depth: 0 23 | 24 | - name: Lint Code Base 25 | uses: github/super-linter@v4 26 | env: 27 | VALIDATE_ALL_CODEBASE: false 28 | DEFAULT_BRANCH: "master" 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.la 4 | *.lo 5 | .deps/ 6 | .libs/ 7 | .* 8 | src/*.d 9 | # Autoconf stuff 10 | libtool 11 | config.* 12 | stamp-h 13 | proxychains4 14 | *.dylib 15 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | original code 2 | N3E7CR34TUR3. 3 | http://proxychains.sourceforge.net 4 | netcreature@users.sourceforge.net 5 | 6 | main.c, remote-dns, thread safety, bugfixes, build system, cleanups 7 | rofl0r. 8 | https://github.com/rofl0r/proxychains 9 | 10 | localnet, bugfixes, macos x support, bsd support, packaging 11 | haad. 12 | https://github.com/haad/proxychains 13 | 14 | localnet-port, bugfixes 15 | jianing yang. 16 | https://github.com/jianingy/proxychains 17 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 675 Mass Ave, Cambridge, MA 02139, 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 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | ProxyChains version history (public releases) 2 | ==================== 3 | 4 | ver 4.2 5 | * Introduce BSD support make proxychains available on (NetBSD, FreeBSD ,OpenBSD and DragonFlyBSD) 6 | * Update pkgsrc-wip proxychains package to 4.2.0 release and make easy to install and use 7 | proxychains 8 | ------------------------------------------------------------------------- 9 | 10 | ver 4.1 11 | * Mac OS X support, create install script. 12 | * thread-safe fixes by @rofl0r 13 | 14 | ------------------------------------------------------------------------- 15 | 16 | ver 4.0 17 | 18 | changed: 19 | * Add a lot of fixes 20 | * localnet-patch 21 | * remote-dns 22 | * thread-safe 23 | ------------------------------------------------------------------------- 24 | 25 | ver 3.1 26 | 27 | changed: 28 | * dns resolver script fix 29 | * prototypes in core.h 30 | 31 | ------------------------------------------------------------------------- 32 | ver 3.0 33 | 34 | added: 35 | * new feature - DNS from behind proxy 36 | * proxyresolv - stand alone command 37 | * proxychains.conf - new option to enable/disable DNS support 38 | 39 | changed: 40 | * bugfixes in core lib 41 | * fixed strict chain 42 | * fixed random chain 43 | * output text 44 | * autotools fix 45 | 46 | ------------------------------------------------------------------------- 47 | ver 2.1 48 | * bugfuxes 49 | 50 | ------------------------------------------------------------------------- 51 | ver 2.0 52 | * major core rewrite 53 | * new config options 54 | 55 | ------------------------------------------------------------------------- 56 | 57 | ver 1.8.2 58 | * minor bugfixes 59 | * improved compilation on FreeBSD & OpenBSD sysems. 60 | * improved compilation on Sun Solaris systems . 61 | * cross platform (UNIX) issues 62 | 63 | ------------------------------------------------------------------------- 64 | 65 | ver 1.8.0 66 | 67 | added: 68 | * Socks5 protocol 69 | * Socks4 protocol 70 | * HTTP proxy auth basic 71 | * Socks4 user auth 72 | * Socks5 user/pass auth 73 | * more chain options (random, strict, dynamic ) 74 | * configurable timeout for TCP connect. 75 | * configurable timeout for TCP read. 76 | * INSTALL file (explains how to install properly) 77 | 78 | changed: 79 | * configuration file entries (proxychains.conf) 80 | * configuration file lookup 81 | 82 | ------------------------------------------------------------------------- 83 | 84 | ver 0.0.1 85 | * TCP calls interception 86 | * HTTP CONNECT proxy protocol. 87 | -------------------------------------------------------------------------------- /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 | prefix = /usr/local 9 | includedir = $(prefix)/include 10 | libdir = $(prefix)/lib 11 | confdir = $(prefix)/etc 12 | datadir = $(prefix)/share 13 | 14 | exec_prefix = $(prefix) 15 | bindir = $(exec_prefix)/bin 16 | zshcompdir = $(datadir)/zsh/site-functions 17 | 18 | SRCS = $(sort $(wildcard src/*.c)) 19 | OBJS = $(SRCS:.c=.o) 20 | LOBJS = src/core.o src/common.o src/libproxychains.o 21 | DEPS = $(OBJS:.o=.d) 22 | 23 | CCFLAGS = -MD -Wall -O2 -g -std=c99 -D_GNU_SOURCE -pipe -DTHREAD_SAFE -Werror 24 | LDFLAGS = -shared -fPIC 25 | INC = 26 | PIC = -fPIC 27 | AR = $(CROSS_COMPILE)ar 28 | RANLIB = $(CROSS_COMPILE)ranlib 29 | 30 | LD_SET_SONAME = -Wl 31 | INSTALL_FLAGS = -D -m 32 | 33 | -include config.mak 34 | 35 | SHARED_LIBS = $(LDSO_PATHNAME) 36 | ALL_LIBS = $(SHARED_LIBS) 37 | PXCHAINS = proxychains4 38 | ALL_TOOLS = $(PXCHAINS) 39 | 40 | CCFLAGS+=$(USER_CFLAGS) $(OS_CFLAGS) 41 | LDFLAGS+=$(USER_LDFLAGS) $(OS_LDFLAGS) 42 | CXXFLAGS+=$(CCFLAGS) $(USER_CFLAGS) $(OS_CFLAGS) 43 | CFLAGS_MAIN=-DLIB_DIR=\"$(libdir)\" -DINSTALL_PREFIX=\"$(prefix)\" -DDLL_NAME=\"$(LDSO_PATHNAME)\" -DSYSCONFDIR=\"$(confdir)\" 44 | 45 | UNAME_S := $(shell uname -s) 46 | ifeq ($(UNAME_S),Linux) 47 | LDSO_PATHNAME = libproxychains.$(LDSO_SUFFIX) 48 | LDSO_SUFFIX = so.4 49 | endif 50 | ifeq ($(UNAME_S),Darwin) 51 | LDSO_PATHNAME = libproxychains4.$(LDSO_SUFFIX) 52 | LDSO_SUFFIX = dylib 53 | endif 54 | 55 | 56 | all: $(ALL_LIBS) $(ALL_TOOLS) 57 | 58 | #install: $(ALL_LIBS:lib/%=$(DESTDIR)$(libdir)/%) $(DESTDIR)$(LDSO_PATHNAME) 59 | install: install-exec install-config install-zsh-completion 60 | 61 | install-exec: 62 | install -d $(DESTDIR)/$(bindir) $(DESTDIR)/$(libdir) $(DESTDIR)/$(confdir) $(DESTDIR)/$(includedir) 63 | install $(INSTALL_FLAGS) 755 $(ALL_TOOLS) src/proxychains src/proxyresolv $(DESTDIR)/$(bindir)/ 64 | install $(INSTALL_FLAGS) 644 $(ALL_LIBS) $(DESTDIR)/$(libdir)/ 65 | 66 | install-config: 67 | install -d $(DESTDIR)/$(confdir) 68 | install $(INSTALL_FLAGS) 644 src/proxychains.conf $(DESTDIR)/$(confdir)/ 69 | 70 | install-zsh-completion: 71 | install -d $(DESTDIR)/$(zshcompdir) 72 | install $(INSTALL_FLAGS) 644 completions/zsh/_proxychains4 -t $(DESTDIR)/$(zshcompdir) 73 | 74 | clean: 75 | rm -f $(ALL_LIBS) 76 | rm -f $(ALL_TOOLS) 77 | rm -f $(OBJS) 78 | rm -f $(DEPS) 79 | 80 | %.o: %.c 81 | $(CC) $(CCFLAGS) $(CFLAGS_MAIN) $(INC) $(PIC) -c -o $@ $< 82 | 83 | $(LDSO_PATHNAME): $(LOBJS) 84 | $(CC) $(LDFLAGS) $(LD_SET_SONAME)$(LDSO_PATHNAME) -o $@ $(LOBJS) 85 | 86 | $(ALL_TOOLS): $(OBJS) 87 | $(CC) src/main.o src/common.o -o $(PXCHAINS) 88 | 89 | .PHONY: all clean install install-exec install-config install-zsh-completion 90 | 91 | -include $(DEPS) 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ProxyChains ver. 4.3.0 README 2 | 3 | ![build-badge](https://github.com/haad/proxychains/actions/workflows/buildci.yml/badge.svg) 4 | 5 | 6 | ProxyChains is a UNIX program, that hooks network-related libc functions 7 | in dynamically linked programs via a preloaded DLL and redirects the 8 | connections through SOCKS4a/5 or HTTP proxies. 9 | 10 | WARNING: this program works only on dynamically linked programs. 11 | also both proxychains and the program to call must use 12 | the same dynamic linker (i.e. same libc) 13 | 14 | ## Known limitations of the current version 15 | 16 | when a process forks, does a DNS lookup in the child, and then uses 17 | the ip in the parent, the corresponding ip mapping will not be found, 18 | this is because the fork can't write back into the parents mapping table. 19 | IRSSI shows this behavior, so you have to pass the resolved ip address 20 | to it. (you can use the proxyresolv script (requires "dig") to do so) 21 | 22 | this means that you can't currently use tor onion urls for irssi. 23 | to solve this issue, an external data store (file, pipe, ...) has to 24 | manage the dns <-> ip mapping. of course there has to be proper locking. 25 | shm_open, mkstemp, are possible candidates for a file based approach, 26 | the other option is to spawn some kind of server process that manages the 27 | map lookups. since connect() etc are hooked, this must not be a TCP server. 28 | 29 | I am reluctant on doing this change, because the described behavior 30 | seems pretty idiotic (doing a fork only for a DNS lookup), and irssi 31 | is currently the only known affected program. 32 | 33 | ## Installation 34 | 35 | ### Using release version 36 | 37 | *Proxychains-4.3.0* are available with pkgsrc to everyone using it on _Linux_, 38 | _NetBSD_, _FreeBSD_, _OpenBSD_, _DragonFlyBSD_ or _Mac OS X_. You just need to install 39 | pkgsrc-wip repository and run 40 | make install 41 | in a wip/proxychains directory. 42 | 43 | You can find out more about pkgsrc on link:http://www.pkgsrc.org[pkgsrc] and about pkgsrc-wip on 44 | link:https://pkgsrc.org/wip[Pkgsrc-wip homepage] 45 | 46 | ### Installing on Mac OS X with homebrew 47 | 48 | You can install current proxychains on Mac OS X with an homebrew. You have to 49 | download unofficial link:https://gist.github.com/3792521[homebrew formula] from 50 | to your BREW_HOME by default /usr/local/Library/Formula/ and run 51 | 52 | ``` 53 | $ brew install proxychains 54 | ``` 55 | 56 | ### Running Current Source code version 57 | 58 | ``` 59 | # needs a working C compiler, preferably gcc 60 | ./configure 61 | make 62 | sudo make install 63 | ``` 64 | 65 | ## Changelog 66 | 67 | *Version (4.x)* removes the dnsresolver script which required a dynamically 68 | linked "dig" binary to be present with remote DNS lookup. 69 | this speeds up any operation involving DNS, as the old script had to use TCP. 70 | additionally it allows to use .onion urls when used with TOR. 71 | also it removed the broken autoconf build system with a simple Makefile. 72 | there's a ./configure script though for convenience. 73 | it also adds support for a config file passed via command line switches/ 74 | environment variables. 75 | 76 | *Version (3.x)* introduces support for DNS resolving through proxy 77 | it supports SOCKS4, SOCKS5 and HTTP CONNECT proxy servers. 78 | 79 | * Auth-types 80 | ** socks - "user/pass", 81 | ** http - "basic" 82 | 83 | ## When to use it 84 | 85 | * When the only way to get "outside" from your LAN is through proxy server. 86 | * To get out from behind restrictive firewall which filters outgoing ports. 87 | * To use two (or more) proxies in chain: 88 | 89 | ``` 90 | like: your_host <--> proxy1 <--> proxy2 <--> target_host 91 | ``` 92 | 93 | * To "proxify" some program with no proxy support built-in (like telnet) 94 | * Access intranet from outside via proxy. 95 | * To use DNS behind proxy. 96 | 97 | ### Some cool features 98 | 99 | * This program can mix different proxy types in the same chain 100 | 101 | ``` 102 | like: your_host <-->socks5 <--> http <--> socks4 <--> target_host 103 | ``` 104 | 105 | * Different chaining options supported 106 | random order from the list ( user defined length of chain ). 107 | exact order (as they appear in the list ) 108 | dynamic order (smart exclude dead proxies from chain) 109 | * You can use it with any TCP client application, even network scanners 110 | yes, yes - you can make portscan via proxy (or chained proxies) 111 | for example with Nmap scanner by fyodor (www.insecure.org/nmap). 112 | 113 | ``` 114 | proxychains nmap -sT -PO -p 80 -iR (find some webservers through proxy) 115 | ``` 116 | 117 | * You can use it with servers, like squid, sendmail, or whatever. 118 | * DNS resolving through proxy. 119 | 120 | ## Configuration 121 | 122 | proxychains looks for configuration in the following order: 123 | 124 | * SOCKS5 proxy host ip and port in environment variable ${PROXYCHAINS_SOCKS5_HOST} ${PROXYCHAINS_SOCKS5_PORT} 125 | (if ${PROXYCHAINS_SOCKS5_PORT} is set, no further configuration will be searched. if ${PROXYCHAINS_SOCKS5_HOST} isn't set, host ip will become "127.0.0.1") 126 | * file listed in environment variable ${PROXYCHAINS_CONF_FILE} or 127 | provided as a -f argument to proxychains script or binary. 128 | * ./proxychains.conf 129 | * $(HOME)/.proxychains/proxychains.conf 130 | * /etc/proxychains.conf 131 | 132 | see more in */etc/proxychains.conf* 133 | 134 | ### Usage Example 135 | 136 | ``` 137 | $ proxychains4 telnet targethost.com 138 | ``` 139 | 140 | in this example it will run telnet through proxy(or chained proxies) 141 | specified by *proxychains.conf* 142 | 143 | ### Usage Example 144 | 145 | ``` 146 | $ proxychains4 -f /etc/proxychains-other.conf targethost2.com 147 | ``` 148 | 149 | in this example it will use different configuration file then *proxychains.conf* 150 | to connect to targethost2.com host. 151 | 152 | ### Usage Example 153 | 154 | ``` 155 | $ proxyresolv targethost.com 156 | ``` 157 | 158 | in this example it will resolve targethost.com through proxy(or chained proxies) 159 | specified by *proxychains.conf* 160 | 161 | ### Usage Example: 162 | 163 | ``` 164 | $ ssh -fN -D 4321 some.example.com 165 | $ PROXYCHAINS_SOCKS5_HOST=127.0.0.1 PROXYCHAINS_SOCKS5_PORT=4321 proxychains zsh 166 | ``` 167 | 168 | in this example, it will run a shell with all traffic proxied through 169 | OpenSSH's "dynamic proxy" (SOCKS5 proxy) on localhost port 4321. 170 | 171 | ### Usage Example: 172 | 173 | ``` 174 | $ export PROXY_DNS_SERVER=8.8.8.8 175 | $ proxychains4 telnet targethost.com 176 | ``` 177 | 178 | in this example, it will telnet to targethost.com using the 8.8.8.8 179 | nameserver supplied by the user through the PROXY_DNS_SERVER 180 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | ProxyChains ver 4.0 TODO 2 | =================== 3 | 4 | - hooks for reentrant dns functions, i.e. gethostbyaddr_r 5 | - shadowsocks support #133 6 | - proxy change according to attempts #156 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /completions/zsh/_proxychains4: -------------------------------------------------------------------------------- 1 | #compdef proxychains4 2 | 3 | _arguments -s -S '1: :{_command_names -e}' '*:: :_normal' 4 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | prefix=/usr/local 4 | develflg=0 5 | 6 | usage() { 7 | echo "supported arguments" 8 | echo "--prefix=/path default: $prefix" 9 | echo "--exec_prefix=/path default: $prefix/bin" 10 | echo "--bindir=/path default: $prefix/bin" 11 | echo "--libdir=/path default: $prefix/lib" 12 | echo "--includedir=/path default: $prefix/include" 13 | echo "--sysconfdir=/path default: $prefix/etc" 14 | echo "--devel default:no (set development mode)" 15 | echo "--help : show this text" 16 | exit 1 17 | } 18 | 19 | spliteq() { 20 | arg=$1 21 | echo "${arg#*=}" 22 | #alternatives echo "$arg" | cut -d= -f2- 23 | # or echo "$arg" | sed 's/[^=]*=//' 24 | } 25 | 26 | parsearg() { 27 | case "$1" in 28 | --prefix=*) prefix=`spliteq $1`;; 29 | --exec_prefix=*) exec_prefix=`spliteq $1`;; 30 | --bindir=*) bindir=`spliteq $1`;; 31 | --libdir=*) libdir=`spliteq $1`;; 32 | --includedir=*) includedir=`spliteq $1`;; 33 | --sysconfdir=*) sysconfdir=`spliteq $1`;; 34 | --devel) develflg=1;; 35 | --help) usage;; 36 | esac 37 | } 38 | 39 | ismac() { 40 | uname -s | grep Darwin 41 | } 42 | 43 | isbsd() { 44 | uname -s | grep BSD 45 | } 46 | 47 | islinux() { 48 | uname -s | grep Linux 49 | } 50 | 51 | while true ; do 52 | case $1 in 53 | -*) parsearg "$1"; shift;; 54 | *) break ;; 55 | esac 56 | done 57 | 58 | if [ -z "$exec_prefix" ] ; then 59 | exec_prefix=$prefix 60 | fi 61 | 62 | if [ -z "$libdir" ] ; then 63 | libdir=$prefix/lib 64 | fi 65 | 66 | if [ -z "$includedir" ] ; then 67 | includedir=$prefix/include 68 | fi 69 | 70 | if [ -z "$sysconfdir" ] ; then 71 | sysconfdir=$prefix/etc 72 | fi 73 | 74 | if [ -z "$bindir" ] ; then 75 | bindir=$exec_prefix/bin 76 | fi 77 | 78 | if [ -z "$CC" ] ; then 79 | CC=cc 80 | fi 81 | 82 | if [ $develflg -eq 1 ]; then 83 | CFLAGS="-Wextra -Wunused -Wuninitialized -Wconversion -fno-common -g -O0 -DDEBUG" 84 | fi 85 | 86 | echo CC?=$CC>config.mak 87 | [ -z "$CPPFLAGS" ] || echo CPPFLAGS?=$CPPFLAGS>>config.mak 88 | [ -z "$CFLAGS" ] || echo USER_CFLAGS?=$CFLAGS>>config.mak 89 | [ -z "$LDFLAGS" ] || echo USER_LDFLAGS?=$LDFLAGS>>config.mak 90 | 91 | echo prefix=$prefix>>config.mak 92 | echo exec_prefix=$exec_prefix>>config.mak 93 | echo bindir=$bindir>>config.mak 94 | echo libdir=$libdir>>config.mak 95 | echo includedir=$includedir>>config.mak 96 | echo sysconfdir=$sysconfdir>>config.mak 97 | 98 | if ismac ; then 99 | arch=`uname -m` 100 | 101 | echo LDSO_SUFFIX=dylib>>config.mak 102 | echo OS_CFLAGS+=-DIS_MAC=1 -arch $arch >>config.mak 103 | echo OS_LDFLAGS+=-arch $arch -lpthread -ldl -Wl,>>config.mak 104 | echo LD_SET_SONAME=-Wl,-install_name,>>config.mak 105 | echo LDSO_SUFFIX=dylib>>config.mak 106 | echo INSTALL_FLAGS=-m>>config.mak 107 | fi 108 | 109 | if islinux ; then 110 | echo OS_LDFLAGS=-pthread -ldl -Wl,--no-as-needed>>config.mak 111 | echo LD_SET_SONAME=-Wl,-soname= >>config.mak 112 | fi 113 | 114 | if isbsd ; then 115 | #echo OS_LDFLAGS= 116 | #echo OS_CFLAGS 117 | echo INSTALL_FLAGS=-m>>config.mak 118 | echo LD_SET_SONAME=-Wl,-rpath,$libdir -install_name,>>config.mak 119 | fi 120 | 121 | echo done, now run make \&\& make install 122 | 123 | 124 | -------------------------------------------------------------------------------- /dist/config.mak: -------------------------------------------------------------------------------- 1 | ### config.mak template for proxychains 2 | ####################################### 3 | 4 | # just copy into proxychains root dir and adapt to your needs. 5 | 6 | prefix = /usr/local/ 7 | libdir = $(prefix)/lib 8 | 9 | exec_prefix = /usr/local 10 | bindir = $(exec_prefix)/bin 11 | 12 | -------------------------------------------------------------------------------- /dist/proxychains.conf: -------------------------------------------------------------------------------- 1 | strict_chain 2 | #proxy_dns 3 | #remote_dns_subnet 224 4 | tcp_read_time_out 15000 5 | tcp_connect_time_out 8000 6 | 7 | localnet 127.0.0.0/255.0.0.0 8 | 9 | 10 | [ProxyList] 11 | http 162.243.184.252 8585 12 | #socks4 184.170.245.148 4145 13 | #raw 162.243.184.252 8585 14 | -------------------------------------------------------------------------------- /proxychains.lsm: -------------------------------------------------------------------------------- 1 | Begin3 2 | Title: ProxyChains 3 | Version: 4.3 4 | Entered-date: 5 | Description: 6 | Keywords: 7 | Author: 8 | Maintained-by: 9 | Primary-site: 10 | Home-page: https://github.com/haad/proxychains 11 | Original-site: 12 | Platforms: Linux and other Unices 13 | Copying-policy: GNU Public License 14 | End 15 | -------------------------------------------------------------------------------- /src/common.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | static int check_path(char *path) { 8 | if(!path) 9 | return 0; 10 | return access(path, R_OK) != -1; 11 | } 12 | 13 | char *get_config_path(char* default_path, char* pbuf, size_t bufsize) { 14 | char buf[512]; 15 | // top priority: user defined path 16 | char *path = default_path; 17 | if(check_path(path)) 18 | return path; 19 | if (!pbuf) 20 | goto err; 21 | 22 | // priority 1: env var PROXYCHAINS_CONF_FILE 23 | path = getenv(PROXYCHAINS_CONF_FILE_ENV_VAR); 24 | if(check_path(path)) 25 | return path; 26 | 27 | // priority 2; proxychains conf in actual dir 28 | path = getcwd(buf, sizeof(buf)); 29 | snprintf(pbuf, bufsize, "%s/%s", path, PROXYCHAINS_CONF_FILE); 30 | path = pbuf; 31 | if(check_path(path)) 32 | return path; 33 | 34 | // priority 3; $HOME/.proxychains/proxychains.conf 35 | path = getenv("HOME"); 36 | snprintf(pbuf, bufsize, "%s/.proxychains/%s", path, PROXYCHAINS_CONF_FILE); 37 | path = pbuf; 38 | if(check_path(path)) 39 | return path; 40 | 41 | // priority 4: $SYSCONFDIR/proxychains.conf 42 | path = SYSCONFDIR "/" PROXYCHAINS_CONF_FILE; 43 | if(check_path(path)) 44 | return path; 45 | 46 | // priority 5: /etc/proxychains.conf 47 | path = "/etc/" PROXYCHAINS_CONF_FILE; 48 | if(check_path(path)) 49 | return path; 50 | 51 | err: 52 | perror("couldn't find configuration file"); 53 | exit(1); 54 | } 55 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | #define PROXYCHAINS_CONF_FILE_ENV_VAR "PROXYCHAINS_CONF_FILE" 2 | #define PROXYCHAINS_QUIET_MODE_ENV_VAR "PROXYCHAINS_QUIET_MODE" 3 | #define PROXYCHAINS_CONF_FILE "proxychains.conf" 4 | #define PROXYCHAINS_SOCKS5_PORT_ENV_VAR "PROXYCHAINS_SOCKS5_PORT" 5 | #define PROXYCHAINS_SOCKS5_HOST_ENV_VAR "PROXYCHAINS_SOCKS5_HOST" 6 | #define PROXYCHAINS_DNS_ENV_VAR "PROXYCHAINS_DNS" 7 | #define LOG_PREFIX "[proxychains] " 8 | 9 | #define PROXYCHAINS_VERSION_MAJOR 4 10 | #define PROXYCHAINS_VERSION_MINOR 3 11 | #define PROXYCHAINS_VERSION_BUGFIX 0 12 | 13 | #include 14 | 15 | char *get_config_path(char* default_path, char* pbuf, size_t bufsize); 16 | -------------------------------------------------------------------------------- /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 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 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 THREAD_SAFE 40 | pthread_mutex_t internal_ips_lock; 41 | 42 | #ifdef __APPLE__ 43 | pthread_mutex_t internal_getsrvbyname_lock; 44 | #endif /* __APPLE__ */ 45 | 46 | #endif /* THREAD_SAFE */ 47 | 48 | #include "core.h" 49 | #include "common.h" 50 | 51 | extern int tcp_read_time_out; 52 | extern int tcp_connect_time_out; 53 | extern int proxychains_quiet_mode; 54 | extern unsigned int remote_dns_subnet; 55 | 56 | internal_ip_lookup_table internal_ips = { 0, 0, NULL }; 57 | 58 | uint32_t dalias_hash(char *s0) { 59 | unsigned char *s = (void *) s0; 60 | uint_fast32_t h = 0; 61 | while(*s) { 62 | h = 16 * h + *s++; 63 | h ^= h >> 24 & 0xf0; 64 | } 65 | return h & 0xfffffff; 66 | } 67 | 68 | uint32_t index_from_internal_ip(ip_type internalip) { 69 | ip_type tmp = internalip; 70 | uint32_t ret; 71 | ret = (uint32_t) (tmp.octet[3] + (tmp.octet[2] << 8) + (tmp.octet[1] << 16)); 72 | ret -= 1; 73 | return ret; 74 | } 75 | 76 | char *string_from_internal_ip(ip_type internalip) { 77 | char *res = NULL; 78 | uint32_t index = index_from_internal_ip(internalip); 79 | MUTEX_LOCK(&internal_ips_lock); 80 | if(index < internal_ips.counter) 81 | res = internal_ips.list[index]->string; 82 | MUTEX_UNLOCK(&internal_ips_lock); 83 | return res; 84 | } 85 | 86 | in_addr_t make_internal_ip(uint32_t index) { 87 | ip_type ret; 88 | index++; // so we can start at .0.0.1 89 | if(index > 0xFFFFFF) 90 | return (in_addr_t) - 1; 91 | ret.octet[0] = remote_dns_subnet & 0xFF; 92 | ret.octet[1] = (index & 0xFF0000) >> 16; 93 | ret.octet[2] = (index & 0xFF00) >> 8; 94 | ret.octet[3] = index & 0xFF; 95 | return (in_addr_t) ret.as_int; 96 | } 97 | 98 | static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 99 | 100 | static int poll_retry(struct pollfd *fds, nfds_t nfsd, int timeout) 101 | { 102 | int ret; 103 | int time_remain = timeout; 104 | int time_elapsed = 0; 105 | 106 | struct timeval start_time; 107 | struct timeval tv; 108 | 109 | gettimeofday(&start_time, NULL); 110 | 111 | do { 112 | //printf("Retry %d\n", time_remain); 113 | ret = poll(fds, nfsd, time_remain); 114 | gettimeofday(&tv, NULL); 115 | time_elapsed = ((int)(tv.tv_sec - start_time.tv_sec) * 1000 + (int)(tv.tv_usec - start_time.tv_usec) / 1000); 116 | //printf("Time elapsed %d\n", time_elapsed); 117 | time_remain = timeout - time_elapsed; 118 | } while(ret == -1 && errno == EINTR && time_remain > 0); 119 | 120 | //if (ret == -1) 121 | //printf("Return %d %d %s\n", ret, errno, strerror(errno)); 122 | return ret; 123 | } 124 | 125 | 126 | static void encode_base_64(char *src, char *dest, int max_len) { 127 | int n, i; 128 | size_t l; 129 | 130 | l = strlen(src); 131 | max_len = (max_len - 1) / 4; 132 | for(i = 0; i < max_len; i++, src += 3, l -= 3) { 133 | switch (l) { 134 | case 0: 135 | break; 136 | case 1: 137 | n = src[0] << 16; 138 | *dest++ = base64[(n >> 18) & 077]; 139 | *dest++ = base64[(n >> 12) & 077]; 140 | *dest++ = '='; 141 | *dest++ = '='; 142 | break; 143 | case 2: 144 | n = src[0] << 16 | src[1] << 8; 145 | *dest++ = base64[(n >> 18) & 077]; 146 | *dest++ = base64[(n >> 12) & 077]; 147 | *dest++ = base64[(n >> 6) & 077]; 148 | *dest++ = '='; 149 | break; 150 | default: 151 | n = src[0] << 16 | src[1] << 8 | src[2]; 152 | *dest++ = base64[(n >> 18) & 077]; 153 | *dest++ = base64[(n >> 12) & 077]; 154 | *dest++ = base64[(n >> 6) & 077]; 155 | *dest++ = base64[n & 077]; 156 | } 157 | if(l < 3) 158 | break; 159 | } 160 | *dest++ = 0; 161 | } 162 | 163 | void proxychains_write_log(char *str, ...) { 164 | char buff[1024*20]; 165 | va_list arglist; 166 | if(!proxychains_quiet_mode) { 167 | va_start(arglist, str); 168 | vsnprintf(buff, sizeof(buff), str, arglist); 169 | va_end(arglist); 170 | fprintf(stderr, "%s", buff); 171 | fflush(stderr); 172 | } 173 | } 174 | 175 | static size_t write_n_bytes(int fd, char *buff, size_t size) { 176 | size_t i = 0; 177 | size_t wrote = 0; 178 | for(;;) { 179 | i = (size_t) write(fd, &buff[wrote], size - wrote); 180 | if(i <= 0) 181 | return i; 182 | wrote += i; 183 | if(wrote == size) 184 | return wrote; 185 | } 186 | } 187 | 188 | static size_t read_n_bytes(int fd, char *buff, size_t size) { 189 | int ready; 190 | size_t i; 191 | struct pollfd pfd[1]; 192 | 193 | pfd[0].fd = fd; 194 | pfd[0].events = POLLIN; 195 | for(i = 0; i < size; i++) { 196 | pfd[0].revents = 0; 197 | ready = poll_retry(pfd, 1, tcp_read_time_out); 198 | if(ready != 1 || !(pfd[0].revents & POLLIN) || 1 != read(fd, &buff[i], 1)) 199 | return 0; 200 | } 201 | return size; 202 | } 203 | 204 | static int timed_connect(int sock, const struct sockaddr *addr, socklen_t len) { 205 | int ret, value; 206 | socklen_t value_len; 207 | struct pollfd pfd[1]; 208 | 209 | pfd[0].fd = sock; 210 | pfd[0].events = POLLOUT; 211 | fcntl(sock, F_SETFL, O_NONBLOCK); 212 | ret = true_connect(sock, addr, len); 213 | PDEBUG("\nconnect ret=%d\n", ret); 214 | 215 | if(ret == -1 && errno == EINPROGRESS) { 216 | ret = poll_retry(pfd, 1, tcp_connect_time_out); 217 | PDEBUG("\npoll ret=%d\n", ret); 218 | if(ret == 1) { 219 | value_len = sizeof(socklen_t); 220 | getsockopt(sock, SOL_SOCKET, SO_ERROR, &value, &value_len); 221 | PDEBUG("\nvalue=%d\n", value); 222 | if(!value) 223 | ret = 0; 224 | else 225 | ret = -1; 226 | } else { 227 | ret = -1; 228 | } 229 | } else { 230 | #ifdef DEBUG 231 | if(ret == -1) 232 | perror("true_connect"); 233 | #endif 234 | if(ret != 0) 235 | ret = -1; 236 | } 237 | 238 | fcntl(sock, F_SETFL, !O_NONBLOCK); 239 | return ret; 240 | } 241 | 242 | 243 | #define INVALID_INDEX 0xFFFFFFFFU 244 | #define HTTP_AUTH_MAX ((0xFF * 2) + 1 + 1) 245 | 246 | static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, char *user, char *pass) { 247 | char *dns_name = NULL; 248 | size_t dns_len = 0; 249 | 250 | PDEBUG("tunnel_to()\n"); 251 | 252 | // we use ip addresses with 224.* to lookup their dns name in our table, to allow remote DNS resolution 253 | // the range 224-255.* is reserved, and it won't go outside (unless the app does some other stuff with 254 | // the results returned from gethostbyname et al.) 255 | // the hardcoded number 224 can now be changed using the config option remote_dns_subnet to i.e. 127 256 | if(ip.octet[0] == remote_dns_subnet) { 257 | dns_name = string_from_internal_ip(ip); 258 | if(!dns_name) 259 | goto err; 260 | dns_len = strlen(dns_name); 261 | if(!dns_len) 262 | goto err; 263 | } 264 | 265 | PDEBUG("host dns %s\n", dns_name ? dns_name : ""); 266 | 267 | size_t ulen = strlen(user); 268 | size_t passlen = strlen(pass); 269 | 270 | if(ulen > 0xFF || passlen > 0xFF || dns_len > 0xFF) { 271 | proxychains_write_log(LOG_PREFIX "error: maximum size of 255 for user/pass or domain name!\n"); 272 | goto err; 273 | } 274 | 275 | size_t len; 276 | unsigned char buff[BUFF_SIZE]; 277 | char ip_buf[16]; 278 | //memset (buff, 0, sizeof(buff)); 279 | 280 | switch (pt) { 281 | case RAW_TYPE: { 282 | return SUCCESS; 283 | } 284 | break; 285 | case HTTP_TYPE:{ 286 | if(!dns_len) { 287 | inet_ntop(AF_INET, &ip.octet[0], ip_buf, sizeof(ip_buf)); 288 | dns_name = ip_buf; 289 | } 290 | 291 | snprintf((char *) buff, sizeof(buff), "CONNECT %s:%d HTTP/1.0\r\n", dns_name, 292 | ntohs(port)); 293 | 294 | if(user[0]) { 295 | // 2 * 0xff: username and pass, plus 1 for ':' and 1 for zero terminator. 296 | char src[HTTP_AUTH_MAX]; 297 | char dst[(4 * HTTP_AUTH_MAX)]; 298 | 299 | memcpy(src, user, ulen); 300 | memcpy(src + ulen, ":", 1); 301 | memcpy(src + ulen + 1, pass, passlen); 302 | src[ulen + 1 + passlen] = 0; 303 | 304 | encode_base_64(src, dst, sizeof(dst)); 305 | strcat((char *) buff, "Proxy-Authorization: Basic "); 306 | strcat((char *) buff, dst); 307 | strcat((char *) buff, "\r\n\r\n"); 308 | } else 309 | strcat((char *) buff, "\r\n"); 310 | 311 | len = strlen((char *) buff); 312 | 313 | if(len != (size_t) send(sock, buff, len, 0)) 314 | goto err; 315 | 316 | len = 0; 317 | // read header byte by byte. 318 | while(len < BUFF_SIZE) { 319 | if(1 == read_n_bytes(sock, (char *) (buff + len), 1)) 320 | len++; 321 | else 322 | goto err; 323 | if(len > 4 && 324 | buff[len - 1] == '\n' && 325 | buff[len - 2] == '\r' && buff[len - 3] == '\n' && buff[len - 4] == '\r') 326 | break; 327 | } 328 | 329 | // if not ok (200) or response greather than BUFF_SIZE return BLOCKED; 330 | if(len == BUFF_SIZE || !(buff[9] == '2' && buff[10] == '0' && buff[11] == '0')) 331 | return BLOCKED; 332 | 333 | return SUCCESS; 334 | } 335 | break; 336 | 337 | case SOCKS4_TYPE:{ 338 | buff[0] = 4; // socks version 339 | buff[1] = 1; // connect command 340 | memcpy(&buff[2], &port, 2); // dest port 341 | if(dns_len) { 342 | ip.octet[0] = 0; 343 | ip.octet[1] = 0; 344 | ip.octet[2] = 0; 345 | ip.octet[3] = 1; 346 | } 347 | memcpy(&buff[4], &ip, 4); // dest host 348 | len = ulen + 1; // username 349 | if(len > 1) 350 | memcpy(&buff[8], user, len); 351 | else { 352 | buff[8] = 0; 353 | } 354 | 355 | // do socksv4a dns resolution on the server 356 | if(dns_len) { 357 | memcpy(&buff[8 + len], dns_name, dns_len + 1); 358 | len += dns_len + 1; 359 | } 360 | 361 | if((len + 8) != write_n_bytes(sock, (char *) buff, (8 + len))) 362 | goto err; 363 | 364 | if(8 != read_n_bytes(sock, (char *) buff, 8)) 365 | goto err; 366 | 367 | if(buff[0] != 0 || buff[1] != 90) 368 | return BLOCKED; 369 | 370 | return SUCCESS; 371 | } 372 | break; 373 | case SOCKS5_TYPE:{ 374 | if(user) { 375 | buff[0] = 5; //version 376 | buff[1] = 2; //nomber of methods 377 | buff[2] = 0; // no auth method 378 | buff[3] = 2; /// auth method -> username / password 379 | if(4 != write_n_bytes(sock, (char *) buff, 4)) 380 | goto err; 381 | } else { 382 | buff[0] = 5; //version 383 | buff[1] = 1; //nomber of methods 384 | buff[2] = 0; // no auth method 385 | if(3 != write_n_bytes(sock, (char *) buff, 3)) 386 | goto err; 387 | } 388 | 389 | if(2 != read_n_bytes(sock, (char *) buff, 2)) 390 | goto err; 391 | 392 | if(buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) { 393 | if(buff[0] == 5 && buff[1] == 0xFF) 394 | return BLOCKED; 395 | else 396 | goto err; 397 | } 398 | 399 | if(buff[1] == 2) { 400 | // authentication 401 | char in[2]; 402 | char out[515]; 403 | char *cur = out; 404 | int c; 405 | *cur++ = 1; // version 406 | c = ulen & 0xFF; 407 | *cur++ = (char)c; 408 | memcpy(cur, user, (size_t)c); 409 | cur += c; 410 | c = passlen & 0xFF; 411 | *cur++ = (char)c; 412 | memcpy(cur, pass, (size_t)c); 413 | cur += c; 414 | 415 | if((size_t)(cur - out) != write_n_bytes(sock, out, (size_t) (cur - out))) 416 | goto err; 417 | 418 | 419 | if(2 != read_n_bytes(sock, in, 2)) 420 | goto err; 421 | if(in[0] != 1 || in[1] != 0) { 422 | if(in[0] != 1) 423 | goto err; 424 | else 425 | return BLOCKED; 426 | } 427 | } 428 | size_t buff_iter = 0; 429 | buff[buff_iter++] = 5; // version 430 | buff[buff_iter++] = 1; // connect 431 | buff[buff_iter++] = 0; // reserved 432 | 433 | if(!dns_len) { 434 | buff[buff_iter++] = 1; // ip v4 435 | memcpy(buff + buff_iter, &ip, 4); // dest host 436 | buff_iter += 4; 437 | } else { 438 | buff[buff_iter++] = 3; //dns 439 | buff[buff_iter++] = dns_len & 0xFF; 440 | memcpy(buff + buff_iter, dns_name, dns_len); 441 | buff_iter += dns_len; 442 | } 443 | 444 | memcpy(buff + buff_iter, &port, 2); // dest port 445 | buff_iter += 2; 446 | 447 | 448 | if(buff_iter != write_n_bytes(sock, (char *) buff, buff_iter)) 449 | goto err; 450 | 451 | if(4 != read_n_bytes(sock, (char *) buff, 4)) 452 | goto err; 453 | 454 | if(buff[0] != 5 || buff[1] != 0) 455 | goto err; 456 | 457 | switch (buff[3]) { 458 | 459 | case 1: 460 | len = 4; 461 | break; 462 | case 4: 463 | len = 16; 464 | break; 465 | case 3: 466 | len = 0; 467 | if(1 != read_n_bytes(sock, (char *) &len, 1)) 468 | goto err; 469 | break; 470 | default: 471 | goto err; 472 | } 473 | 474 | if(len + 2 != read_n_bytes(sock, (char *) buff, len + 2)) 475 | goto err; 476 | 477 | return SUCCESS; 478 | } 479 | break; 480 | } 481 | 482 | err: 483 | return SOCKET_ERROR; 484 | } 485 | 486 | #define TP " ... " 487 | #define DT "Dynamic chain" 488 | #define ST "Strict chain" 489 | #define RT "Random chain" 490 | 491 | static int start_chain(int *fd, proxy_data * pd, char *begin_mark) { 492 | struct sockaddr_in addr; 493 | char ip_buf[16]; 494 | 495 | *fd = socket(PF_INET, SOCK_STREAM, 0); 496 | if(*fd == -1) 497 | goto error; 498 | 499 | inet_ntop(AF_INET, &pd->ip.octet[0], ip_buf, sizeof(ip_buf)); 500 | proxychains_write_log(LOG_PREFIX "%s " TP " %s:%d ", 501 | begin_mark, ip_buf, htons(pd->port)); 502 | pd->ps = PLAY_STATE; 503 | memset(&addr, 0, sizeof(addr)); 504 | addr.sin_family = AF_INET; 505 | addr.sin_addr.s_addr = (in_addr_t) pd->ip.as_int; 506 | addr.sin_port = pd->port; 507 | if(timed_connect(*fd, (struct sockaddr *) &addr, sizeof(addr))) { 508 | pd->ps = DOWN_STATE; 509 | goto error1; 510 | } 511 | pd->ps = BUSY_STATE; 512 | return SUCCESS; 513 | error1: 514 | proxychains_write_log(TP " timeout\n"); 515 | error: 516 | if(*fd != -1) 517 | close(*fd); 518 | return SOCKET_ERROR; 519 | } 520 | 521 | unsigned int get_rand_int(unsigned int range){ 522 | static FILE *fp; 523 | unsigned int randval; 524 | if (!fp) { 525 | fp = fopen("/dev/urandom", "r"); 526 | } 527 | if(fread(&randval, sizeof(randval), 1, fp)) { 528 | return (randval % range); 529 | } else { 530 | srand((unsigned int)time(NULL)); 531 | return ((unsigned int)rand() % range); 532 | } 533 | } 534 | 535 | static proxy_data *select_proxy(select_type how, proxy_data * pd, unsigned int proxy_count, unsigned int *offset) { 536 | unsigned int i = 0, k = 0; 537 | 538 | if(*offset >= proxy_count) 539 | return NULL; 540 | switch (how) { 541 | case RANDOMLY: 542 | 543 | do { 544 | k++; 545 | i = 0 + get_rand_int(proxy_count); 546 | } while(pd[i].ps != PLAY_STATE && k < proxy_count * 100); 547 | break; 548 | case FIFOLY: 549 | for(i = *offset; i < proxy_count; i++) { 550 | if(pd[i].ps == PLAY_STATE) { 551 | *offset = i; 552 | break; 553 | } 554 | } 555 | default: 556 | break; 557 | } 558 | if(i >= proxy_count) 559 | i = 0; 560 | return (pd[i].ps == PLAY_STATE) ? &pd[i] : NULL; 561 | } 562 | 563 | 564 | static void release_all(proxy_data * pd, unsigned int proxy_count) { 565 | unsigned int i; 566 | for(i = 0; i < proxy_count; i++) 567 | pd[i].ps = PLAY_STATE; 568 | return; 569 | } 570 | 571 | static void release_busy(proxy_data * pd, unsigned int proxy_count) { 572 | unsigned int i; 573 | for(i = 0; i < proxy_count; i++) 574 | if(pd[i].ps == BUSY_STATE) 575 | pd[i].ps = PLAY_STATE; 576 | return; 577 | } 578 | 579 | static unsigned int calc_alive(proxy_data * pd, unsigned int proxy_count) { 580 | unsigned int i, alive_count = 0; 581 | release_busy(pd, proxy_count); 582 | for(i = 0; i < proxy_count; i++) 583 | if(pd[i].ps == PLAY_STATE) 584 | alive_count++; 585 | return alive_count; 586 | } 587 | 588 | static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) { 589 | int retcode = -1; 590 | char *hostname; 591 | char ip_buf[16]; 592 | 593 | PDEBUG("chain_step()\n"); 594 | 595 | if(pto->ip.octet[0] == remote_dns_subnet) { 596 | hostname = string_from_internal_ip(pto->ip); 597 | if(!hostname) 598 | goto usenumericip; 599 | } else { 600 | usenumericip: 601 | inet_ntop(AF_INET, &pto->ip.octet[0], ip_buf, sizeof(ip_buf)); 602 | hostname = ip_buf; 603 | } 604 | 605 | proxychains_write_log(TP " %s:%d ", hostname, htons(pto->port)); 606 | retcode = tunnel_to(ns, pto->ip, pto->port, pfrom->pt, pfrom->user, pfrom->pass); 607 | switch (retcode) { 608 | case SUCCESS: 609 | pto->ps = BUSY_STATE; 610 | break; 611 | case BLOCKED: 612 | pto->ps = BLOCKED_STATE; 613 | proxychains_write_log("<--denied\n"); 614 | close(ns); 615 | break; 616 | case SOCKET_ERROR: 617 | pto->ps = DOWN_STATE; 618 | proxychains_write_log("<--socket error or timeout!\n"); 619 | close(ns); 620 | break; 621 | } 622 | return retcode; 623 | } 624 | 625 | int connect_proxy_chain(int sock, ip_type target_ip, 626 | unsigned short target_port, proxy_data * pd, 627 | unsigned int proxy_count, chain_type ct, unsigned int max_chain) { 628 | proxy_data p4; 629 | proxy_data *p1, *p2, *p3; 630 | int ns = -1; 631 | unsigned int offset = 0; 632 | unsigned int alive_count = 0; 633 | unsigned int curr_len = 0; 634 | 635 | p3 = &p4; 636 | 637 | PDEBUG("connect_proxy_chain\n"); 638 | 639 | again: 640 | 641 | switch (ct) { 642 | case DYNAMIC_TYPE: 643 | calc_alive(pd, proxy_count); 644 | offset = 0; 645 | do { 646 | if(!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) 647 | goto error_more; 648 | } while(SUCCESS != start_chain(&ns, p1, DT) && offset < proxy_count); 649 | for(;;) { 650 | p2 = select_proxy(FIFOLY, pd, proxy_count, &offset); 651 | if(!p2) 652 | break; 653 | if(SUCCESS != chain_step(ns, p1, p2)) { 654 | PDEBUG("GOTO AGAIN 1\n"); 655 | goto again; 656 | } 657 | p1 = p2; 658 | } 659 | //proxychains_write_log(TP); 660 | p3->ip = target_ip; 661 | p3->port = target_port; 662 | if(SUCCESS != chain_step(ns, p1, p3)) 663 | goto error; 664 | break; 665 | 666 | case STRICT_TYPE: 667 | calc_alive(pd, proxy_count); 668 | offset = 0; 669 | if(!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) { 670 | PDEBUG("select_proxy failed\n"); 671 | goto error_strict; 672 | } 673 | if(SUCCESS != start_chain(&ns, p1, ST)) { 674 | PDEBUG("start_chain failed\n"); 675 | goto error_strict; 676 | } 677 | while(offset < proxy_count) { 678 | if(!(p2 = select_proxy(FIFOLY, pd, proxy_count, &offset))) 679 | break; 680 | if(SUCCESS != chain_step(ns, p1, p2)) { 681 | PDEBUG("chain_step failed\n"); 682 | goto error_strict; 683 | } 684 | p1 = p2; 685 | } 686 | //proxychains_write_log(TP); 687 | p3->ip = target_ip; 688 | p3->port = target_port; 689 | if(SUCCESS != chain_step(ns, p1, p3)) 690 | goto error; 691 | break; 692 | 693 | case RANDOM_TYPE: 694 | alive_count = calc_alive(pd, proxy_count); 695 | if(alive_count < max_chain) 696 | goto error_more; 697 | curr_len = offset = 0; 698 | do { 699 | if(!(p1 = select_proxy(RANDOMLY, pd, proxy_count, &offset))) 700 | goto error_more; 701 | } while(SUCCESS != start_chain(&ns, p1, RT) && offset < max_chain); 702 | while(++curr_len < max_chain) { 703 | if(!(p2 = select_proxy(RANDOMLY, pd, proxy_count, &offset))) 704 | goto error_more; 705 | if(SUCCESS != chain_step(ns, p1, p2)) { 706 | PDEBUG("GOTO AGAIN 2\n"); 707 | goto again; 708 | } 709 | p1 = p2; 710 | } 711 | //proxychains_write_log(TP); 712 | p3->ip = target_ip; 713 | p3->port = target_port; 714 | if(SUCCESS != chain_step(ns, p1, p3)) 715 | goto error; 716 | } 717 | 718 | proxychains_write_log(TP " OK\n"); 719 | dup2(ns, sock); 720 | close(ns); 721 | return 0; 722 | error: 723 | if(ns != -1) 724 | close(ns); 725 | errno = ECONNREFUSED; // for nmap ;) 726 | return -1; 727 | 728 | error_more: 729 | proxychains_write_log("\n!!!need more proxies!!!\n"); 730 | error_strict: 731 | PDEBUG("error\n"); 732 | 733 | release_all(pd, proxy_count); 734 | if(ns != -1) 735 | close(ns); 736 | errno = ETIMEDOUT; 737 | return -1; 738 | } 739 | 740 | static const ip_type local_host = { {127, 0, 0, 1} }; 741 | 742 | char hostname[256]; // default maximum length of hostname in linux 743 | struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* data) { 744 | char buff[256]; 745 | uint32_t i, hash; 746 | // yep, new_mem never gets freed. once you passed a fake ip to the client, you can't "retreat" it 747 | void *new_mem; 748 | size_t l; 749 | struct hostent *hp; 750 | 751 | data->resolved_addr_p[0] = (char *) &data->resolved_addr; 752 | data->resolved_addr_p[1] = NULL; 753 | 754 | data->hostent_space.h_addr_list = data->resolved_addr_p; 755 | 756 | data->resolved_addr = 0; 757 | 758 | gethostname(buff, sizeof(buff)); 759 | 760 | if(!strcmp(buff, name)) { 761 | data->resolved_addr = inet_addr(buff); 762 | if(data->resolved_addr == (in_addr_t) (-1)) 763 | data->resolved_addr = (in_addr_t) (local_host.as_int); 764 | 765 | snprintf(hostname,sizeof hostname, "%s", name); 766 | data->hostent_space.h_name = hostname; 767 | data->hostent_space.h_length = sizeof (in_addr_t); 768 | data->hostent_space.h_addrtype = AF_INET; 769 | 770 | return &data->hostent_space; 771 | } 772 | 773 | memset(buff, 0, sizeof(buff)); 774 | 775 | while((hp = gethostent())) 776 | if(!strcmp(hp->h_name, name)) 777 | return hp; 778 | 779 | hash = dalias_hash((char *) name); 780 | 781 | MUTEX_LOCK(&internal_ips_lock); 782 | 783 | // see if we already have this dns entry saved. 784 | if(internal_ips.counter) { 785 | for(i = 0; i < internal_ips.counter; i++) { 786 | if(internal_ips.list[i]->hash == hash && !strcmp(name, internal_ips.list[i]->string)) { 787 | data->resolved_addr = make_internal_ip(i); 788 | PDEBUG("got cached ip for %s\n", name); 789 | goto have_ip; 790 | } 791 | } 792 | } 793 | 794 | // grow list if needed. 795 | if(internal_ips.capa < internal_ips.counter + 1) { 796 | PDEBUG("realloc\n"); 797 | new_mem = realloc(internal_ips.list, (internal_ips.capa + 16) * sizeof(void *)); 798 | if(new_mem) { 799 | internal_ips.capa += 16; 800 | internal_ips.list = new_mem; 801 | } else { 802 | oom: 803 | proxychains_write_log("out of mem\n"); 804 | goto err_plus_unlock; 805 | } 806 | } 807 | 808 | data->resolved_addr = make_internal_ip(internal_ips.counter); 809 | if(data->resolved_addr == (in_addr_t) - 1) 810 | goto err_plus_unlock; 811 | 812 | l = strlen(name); 813 | new_mem = malloc(sizeof(string_hash_tuple) + l + 1); 814 | if(!new_mem) 815 | goto oom; 816 | 817 | PDEBUG("creating new entry %d for ip of %s\n", (int) internal_ips.counter, name); 818 | 819 | internal_ips.list[internal_ips.counter] = new_mem; 820 | internal_ips.list[internal_ips.counter]->hash = hash; 821 | 822 | internal_ips.list[internal_ips.counter]->string = (char *) new_mem + sizeof(string_hash_tuple); 823 | 824 | memcpy(internal_ips.list[internal_ips.counter]->string, name, l + 1); 825 | 826 | internal_ips.counter += 1; 827 | 828 | have_ip: 829 | 830 | MUTEX_UNLOCK(&internal_ips_lock); 831 | 832 | strncpy(data->addr_name, name, sizeof(data->addr_name) - 1); 833 | 834 | data->hostent_space.h_name = data->addr_name; 835 | data->hostent_space.h_length = sizeof(in_addr_t); 836 | data->hostent_space.h_addrtype = AF_INET; 837 | 838 | return &data->hostent_space; 839 | 840 | err_plus_unlock: 841 | MUTEX_UNLOCK(&internal_ips_lock); 842 | return NULL; 843 | } 844 | 845 | struct addrinfo_data { 846 | struct addrinfo addrinfo_space; 847 | struct sockaddr sockaddr_space; 848 | char addr_name[256]; 849 | }; 850 | 851 | void proxy_freeaddrinfo(struct addrinfo *res) { 852 | free(res); 853 | } 854 | 855 | void proxy_getservbyname(const char * service, struct servent *se_buf, 856 | char * buf, size_t buf_len, struct servent **se_result) 857 | { 858 | 859 | #ifdef __linux__ 860 | getservbyname_r(service, NULL, se_buf, buf, buf_len, se_result); 861 | #endif 862 | 863 | #ifdef __APPLE__ 864 | struct servent *se; 865 | 866 | MUTEX_LOCK(&internal_getsrvbyname_lock); 867 | if(service) { 868 | se = getservbyname(service, NULL); 869 | 870 | if ( se != NULL ) { 871 | memcpy(se_buf, se, buf_len); 872 | *se_result = se_buf; 873 | } else { 874 | *se_result = NULL; 875 | } 876 | } 877 | MUTEX_UNLOCK(&internal_getsrvbyname_lock); 878 | #endif /* __APPLE__ */ 879 | } 880 | 881 | int proxy_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { 882 | struct gethostbyname_data ghdata; 883 | struct addrinfo_data *space; 884 | struct servent *se = NULL; 885 | struct hostent *hp = NULL; 886 | struct servent se_buf; 887 | struct addrinfo *p; 888 | char buf[1024]; 889 | int port; 890 | 891 | // printf("proxy_getaddrinfo node %s service %s\n",node,service); 892 | space = calloc(1, sizeof(struct addrinfo_data)); 893 | if(!space) 894 | return 1; 895 | 896 | if(node && !inet_aton(node, &((struct sockaddr_in *) &space->sockaddr_space)->sin_addr)) { 897 | hp = proxy_gethostbyname(node, &ghdata); 898 | if(hp) { 899 | memcpy(&((struct sockaddr_in *) &space->sockaddr_space)->sin_addr, 900 | *(hp->h_addr_list), sizeof(in_addr_t)); 901 | } else { 902 | free(space); 903 | return 1; 904 | } 905 | } 906 | if(service) 907 | proxy_getservbyname(service, &se_buf, buf, sizeof(buf), &se); 908 | 909 | port = se ? se->s_port : htons((uint16_t)atoi(service ? service : "0")); 910 | ((struct sockaddr_in *) &space->sockaddr_space)->sin_port = (in_port_t)port; 911 | 912 | *res = p = &space->addrinfo_space; 913 | assert((size_t)p == (size_t) space); 914 | 915 | p->ai_addr = &space->sockaddr_space; 916 | if(node) 917 | strncpy(space->addr_name, node, sizeof(space->addr_name) - 1); 918 | p->ai_canonname = space->addr_name; 919 | p->ai_next = NULL; 920 | p->ai_family = space->sockaddr_space.sa_family = AF_INET; 921 | p->ai_addrlen = sizeof(space->sockaddr_space); 922 | 923 | if(hints) { 924 | p->ai_socktype = hints->ai_socktype; 925 | p->ai_flags = hints->ai_flags; 926 | p->ai_protocol = hints->ai_protocol; 927 | } else { 928 | #ifdef BSD 929 | p->ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG); 930 | #else 931 | p->ai_flags = (AI_ADDRCONFIG); 932 | #endif 933 | } 934 | 935 | return 0; 936 | } 937 | -------------------------------------------------------------------------------- /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 | 19 | #ifndef __CORE_HEADER 20 | #define __CORE_HEADER 21 | #define BUFF_SIZE 8*1024 // used to read responses from proxies. 22 | #define MAX_LOCALNET 64 23 | #define MAX_DNAT 64 24 | 25 | typedef union { 26 | unsigned char octet[4]; 27 | uint32_t as_int; 28 | } ip_type; 29 | 30 | typedef struct { 31 | uint32_t hash; 32 | char* string; 33 | } string_hash_tuple; 34 | 35 | typedef struct { 36 | uint32_t counter; 37 | uint32_t capa; 38 | string_hash_tuple** list; 39 | } internal_ip_lookup_table; 40 | 41 | extern internal_ip_lookup_table internal_ips; 42 | 43 | #ifdef THREAD_SAFE 44 | #include 45 | 46 | extern pthread_mutex_t internal_ips_lock; 47 | extern pthread_mutex_t internal_getsrvbyname_lock; 48 | 49 | # define MUTEX_LOCK(x) pthread_mutex_lock(x) 50 | # define MUTEX_UNLOCK(x) pthread_mutex_unlock(x) 51 | # define MUTEX_INIT(x,y) pthread_mutex_init(x, y) 52 | #else 53 | # define MUTEX_LOCK(x) 54 | # define MUTEX_UNLOCK(x) 55 | # define MUTEX_INIT(x,y) 56 | #endif 57 | 58 | /*error codes*/ 59 | typedef enum { 60 | SUCCESS=0, 61 | MEMORY_FAIL, // malloc failed 62 | SOCKET_ERROR, // look errno for more 63 | CHAIN_DOWN, // no proxy in chain responds to tcp 64 | CHAIN_EMPTY, // if proxy_count = 0 65 | BLOCKED // target's port blocked on last proxy in the chain 66 | } ERR_CODE; 67 | 68 | typedef enum { 69 | HTTP_TYPE, 70 | RAW_TYPE, 71 | SOCKS4_TYPE, 72 | SOCKS5_TYPE 73 | } proxy_type; 74 | 75 | typedef enum { 76 | DYNAMIC_TYPE, 77 | STRICT_TYPE, 78 | RANDOM_TYPE} 79 | chain_type; 80 | 81 | typedef enum { 82 | PLAY_STATE, 83 | DOWN_STATE, 84 | BLOCKED_STATE, 85 | BUSY_STATE 86 | } proxy_state; 87 | 88 | typedef enum { 89 | RANDOMLY, 90 | FIFOLY 91 | } select_type; 92 | 93 | typedef struct { 94 | struct in_addr in_addr, netmask; 95 | unsigned short port; 96 | } localaddr_arg; 97 | 98 | typedef struct { 99 | struct in_addr orig_dst, new_dst; 100 | unsigned short orig_port, new_port; 101 | } dnat_arg; 102 | 103 | typedef struct { 104 | ip_type ip; 105 | unsigned short port; 106 | proxy_type pt; 107 | proxy_state ps; 108 | char user[256]; 109 | char pass[256]; 110 | } proxy_data; 111 | 112 | int connect_proxy_chain (int, ip_type, unsigned short, proxy_data *, unsigned int, 113 | chain_type, unsigned int); 114 | 115 | void proxychains_write_log(char *, ...); 116 | 117 | typedef int (*connect_t)(int, const struct sockaddr *, socklen_t); 118 | typedef struct hostent* (*gethostbyname_t)(const char *); 119 | typedef int (*freeaddrinfo_t)(struct addrinfo *); 120 | 121 | #if (defined __linux__) || (defined __APPLE__) 122 | typedef struct hostent *(*gethostbyaddr_t) (const void *, socklen_t, int); 123 | #else 124 | typedef struct hostent *(*gethostbyaddr_t) (const char *, socklen_t, int); 125 | #endif 126 | 127 | typedef int (*getaddrinfo_t)(const char *, const char *, const struct addrinfo *, 128 | struct addrinfo **); 129 | typedef int (*getnameinfo_t) (const struct sockaddr *, socklen_t, char *, 130 | socklen_t, char *, socklen_t, int); 131 | 132 | 133 | extern connect_t true_connect; 134 | extern gethostbyname_t true_gethostbyname; 135 | extern getaddrinfo_t true_getaddrinfo; 136 | extern freeaddrinfo_t true_freeaddrinfo; 137 | extern getnameinfo_t true_getnameinfo; 138 | extern gethostbyaddr_t true_gethostbyaddr; 139 | 140 | struct gethostbyname_data { 141 | struct hostent hostent_space; 142 | in_addr_t resolved_addr; 143 | char *resolved_addr_p[2]; 144 | char addr_name[1024 * 8]; 145 | }; 146 | 147 | struct hostent* proxy_gethostbyname(const char *, struct gethostbyname_data *); 148 | void proxy_getservbyname(const char *, struct servent *, char *, size_t, struct servent **); 149 | int proxy_getaddrinfo(const char *, const char *, const struct addrinfo *, struct addrinfo **); 150 | void proxy_freeaddrinfo(struct addrinfo *); 151 | 152 | #ifdef DEBUG 153 | # define PDEBUG(fmt, args...) do { fprintf(stderr,"DEBUG:"fmt, ## args); fflush(stderr); } while(0) 154 | #else 155 | # define PDEBUG(fmt, args...) do {} while (0) 156 | #endif 157 | 158 | #endif 159 | -------------------------------------------------------------------------------- /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 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | #include "core.h" 38 | #include "common.h" 39 | 40 | #define satosin(x) ((struct sockaddr_in *) &(x)) 41 | #define SOCKADDR(x) (satosin(x)->sin_addr.s_addr) 42 | #define SOCKADDR_2(x) (satosin(x)->sin_addr) 43 | #define SOCKPORT(x) (satosin(x)->sin_port) 44 | #define SOCKFAMILY(x) (satosin(x)->sin_family) 45 | #define MAX_CHAIN 512 46 | 47 | connect_t true_connect; 48 | gethostbyname_t true_gethostbyname; 49 | getaddrinfo_t true_getaddrinfo; 50 | freeaddrinfo_t true_freeaddrinfo; 51 | getnameinfo_t true_getnameinfo; 52 | gethostbyaddr_t true_gethostbyaddr; 53 | 54 | int tcp_read_time_out; 55 | int tcp_connect_time_out; 56 | int proxychains_got_chain_data = 0; 57 | int proxychains_quiet_mode = 0; 58 | int proxychains_resolver = 0; 59 | 60 | unsigned int proxychains_proxy_count = 0; 61 | unsigned int proxychains_max_chain = 1; 62 | unsigned int remote_dns_subnet = 224; 63 | 64 | localaddr_arg localnet_addr[MAX_LOCALNET]; 65 | chain_type proxychains_ct; 66 | proxy_data proxychains_pd[MAX_CHAIN]; 67 | 68 | size_t num_localnet_addr = 0; 69 | dnat_arg dnats[MAX_DNAT]; 70 | size_t num_dnats = 0; 71 | 72 | #ifdef THREAD_SAFE 73 | pthread_once_t init_once = PTHREAD_ONCE_INIT; 74 | #endif 75 | static int init_l = 0; 76 | 77 | static void load_default_settings(chain_type *ct); 78 | static inline void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_type * ct); 79 | static void simple_socks5_env(proxy_data * pd, unsigned int *proxy_count, chain_type * ct); 80 | 81 | static void* load_sym(char* symname, void* proxyfunc) { 82 | 83 | void *funcptr = dlsym(RTLD_NEXT, symname); 84 | if(!funcptr) { 85 | fprintf(stderr, "Cannot load symbol '%s' %s\n", symname, dlerror()); 86 | exit(1); 87 | } else { 88 | PDEBUG("loaded symbol '%s'" " real addr %p wrapped addr %p\n", symname, funcptr, proxyfunc); 89 | } 90 | if(funcptr == proxyfunc) { 91 | PDEBUG("circular reference detected, aborting!\n"); 92 | abort(); 93 | } 94 | return funcptr; 95 | } 96 | 97 | #define INIT() init_lib_wrapper(__FUNCTION__) 98 | 99 | #define SETUP_SYM(X) do { true_ ## X = load_sym( # X, X ); } while(0) 100 | 101 | static void do_init(void) { 102 | MUTEX_INIT(&internal_ips_lock, NULL); 103 | 104 | #ifdef __APPLE__ 105 | MUTEX_INIT(&internal_getsrvbyname_lock, NULL); 106 | #endif 107 | 108 | /* check for simple SOCKS5 proxy setup */ 109 | simple_socks5_env(proxychains_pd, &proxychains_proxy_count, &proxychains_ct); 110 | 111 | /* read the config file */ 112 | get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct); 113 | 114 | proxychains_write_log(LOG_PREFIX "DLL init\n"); 115 | SETUP_SYM(connect); 116 | SETUP_SYM(gethostbyname); 117 | SETUP_SYM(getaddrinfo); 118 | SETUP_SYM(freeaddrinfo); 119 | SETUP_SYM(gethostbyaddr); 120 | SETUP_SYM(getnameinfo); 121 | init_l = 1; 122 | } 123 | 124 | static void init_lib_wrapper(const char* caller) { 125 | #ifndef DEBUG 126 | (void) caller; 127 | #endif 128 | #ifndef THREAD_SAFE 129 | if(init_l) return; 130 | PDEBUG("%s called from %s\n", __FUNCTION__, caller); 131 | do_init(); 132 | #else 133 | if(!init_l) PDEBUG("%s called from %s\n", __FUNCTION__, caller); 134 | pthread_once(&init_once, do_init); 135 | #endif 136 | } 137 | 138 | /* if we use gcc >= 3, we can instruct the dynamic loader 139 | * to call init_lib at link time. otherwise it gets loaded 140 | * lazily, which has the disadvantage that there's a potential 141 | * race condition if 2 threads call it before init_l is set 142 | * and PTHREAD support was disabled */ 143 | #if __GNUC__ > 2 144 | __attribute__((constructor)) 145 | static void gcc_init(void) { 146 | INIT(); 147 | } 148 | #endif 149 | 150 | FILE * 151 | open_config_file() { 152 | char home_conf[MAXPATHLEN], prefix_conf[MAXPATHLEN]; 153 | FILE *file; 154 | 155 | snprintf(home_conf, 256, "%s/.proxychains/proxychains.conf", getenv("HOME")); 156 | snprintf(prefix_conf, 256, "%s/etc/proxychains.conf", INSTALL_PREFIX); 157 | 158 | if(!(file = fopen("./proxychains.conf", "r"))) { 159 | if(!(file = fopen(home_conf, "r"))) { 160 | if(!(file = fopen(prefix_conf, "r"))) { 161 | if(!(file = fopen("/etc/proxychains.conf", "r"))) { 162 | perror("Can't locate proxychains.conf"); 163 | exit(1); 164 | } 165 | } 166 | } 167 | } 168 | 169 | return file; 170 | } 171 | 172 | /* default settings common to get_chain_data and simple_socks5_env */ 173 | static void load_default_settings(chain_type *ct) { 174 | char *env; 175 | 176 | tcp_read_time_out = 4 * 1000; 177 | tcp_connect_time_out = 10 * 1000; 178 | *ct = DYNAMIC_TYPE; 179 | 180 | env = getenv(PROXYCHAINS_QUIET_MODE_ENV_VAR); 181 | if(env && *env == '1') 182 | proxychains_quiet_mode = 1; 183 | } 184 | 185 | /* get configuration from config file */ 186 | static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_type * ct) { 187 | unsigned int count = 0; 188 | int port_n = 0, list = 0; 189 | char buff[1024], type[1024], host[1024], user[1024]; 190 | char *env; 191 | char local_in_addr_port[32]; 192 | char local_in_addr[32], local_in_port[32], local_netmask[32]; 193 | char dnat_orig_addr_port[32], dnat_new_addr_port[32]; 194 | char dnat_orig_addr[32], dnat_orig_port[32], dnat_new_addr[32], dnat_new_port[32]; 195 | FILE *file = NULL; 196 | 197 | if(proxychains_got_chain_data) 198 | return; 199 | 200 | load_default_settings(ct); 201 | 202 | env = get_config_path(getenv(PROXYCHAINS_CONF_FILE_ENV_VAR), buff, sizeof(buff)); 203 | file = fopen(env, "r"); 204 | 205 | while(fgets(buff, sizeof(buff), file)) { 206 | if(buff[0] != '\n' && buff[strspn(buff, " ")] != '#') { 207 | /* proxylist has to come last */ 208 | if(list) { 209 | if(count >= MAX_CHAIN) 210 | break; 211 | 212 | memset(&pd[count], 0, sizeof(proxy_data)); 213 | 214 | pd[count].ps = PLAY_STATE; 215 | port_n = 0; 216 | 217 | sscanf(buff, "%s %s %d %s %s", type, host, &port_n, pd[count].user, pd[count].pass); 218 | 219 | pd[count].ip.as_int = (uint32_t) inet_addr(host); 220 | pd[count].port = htons((unsigned short) port_n); 221 | 222 | if(!strcmp(type, "http")) { 223 | pd[count].pt = HTTP_TYPE; 224 | } else if(!strcmp(type, "raw")) { 225 | pd[count].pt = RAW_TYPE; 226 | } else if(!strcmp(type, "socks4")) { 227 | pd[count].pt = SOCKS4_TYPE; 228 | } else if(!strcmp(type, "socks5")) { 229 | pd[count].pt = SOCKS5_TYPE; 230 | } else 231 | continue; 232 | 233 | if(pd[count].ip.as_int && port_n && pd[count].ip.as_int != (uint32_t) - 1) 234 | count++; 235 | } else { 236 | if(strstr(buff, "[ProxyList]")) { 237 | list = 1; 238 | } else if(strstr(buff, "random_chain")) { 239 | *ct = RANDOM_TYPE; 240 | } else if(strstr(buff, "strict_chain")) { 241 | *ct = STRICT_TYPE; 242 | } else if(strstr(buff, "dynamic_chain")) { 243 | *ct = DYNAMIC_TYPE; 244 | } else if(strstr(buff, "tcp_read_time_out")) { 245 | sscanf(buff, "%s %d", user, &tcp_read_time_out); 246 | } else if(strstr(buff, "tcp_connect_time_out")) { 247 | sscanf(buff, "%s %d", user, &tcp_connect_time_out); 248 | } else if(strstr(buff, "remote_dns_subnet")) { 249 | sscanf(buff, "%s %d", user, &remote_dns_subnet); 250 | if(remote_dns_subnet >= 256) { 251 | fprintf(stderr, 252 | "remote_dns_subnet: invalid value. requires a number between 0 and 255.\n"); 253 | exit(1); 254 | } 255 | } else if(strstr(buff, "localnet")) { 256 | if(sscanf(buff, "%s %21[^/]/%15s", user, local_in_addr_port, local_netmask) < 3) { 257 | fprintf(stderr, "localnet format error"); 258 | exit(1); 259 | } 260 | /* clean previously used buffer */ 261 | memset(local_in_port, 0, sizeof(local_in_port) / sizeof(local_in_port[0])); 262 | 263 | if(sscanf(local_in_addr_port, "%15[^:]:%5s", local_in_addr, local_in_port) < 2) { 264 | PDEBUG("added localnet: netaddr=%s, netmask=%s\n", 265 | local_in_addr, local_netmask); 266 | } else { 267 | PDEBUG("added localnet: netaddr=%s, port=%s, netmask=%s\n", 268 | local_in_addr, local_in_port, local_netmask); 269 | } 270 | if(num_localnet_addr < MAX_LOCALNET) { 271 | int error; 272 | error = 273 | inet_pton(AF_INET, local_in_addr, 274 | &localnet_addr[num_localnet_addr].in_addr); 275 | if(error <= 0) { 276 | fprintf(stderr, "localnet address error\n"); 277 | exit(1); 278 | } 279 | error = 280 | inet_pton(AF_INET, local_netmask, 281 | &localnet_addr[num_localnet_addr].netmask); 282 | if(error <= 0) { 283 | fprintf(stderr, "localnet netmask error\n"); 284 | exit(1); 285 | } 286 | if(local_in_port[0]) { 287 | localnet_addr[num_localnet_addr].port = 288 | (unsigned short) atoi(local_in_port); 289 | } else { 290 | localnet_addr[num_localnet_addr].port = 0; 291 | } 292 | ++num_localnet_addr; 293 | } else { 294 | fprintf(stderr, "# of localnet exceed %d.\n", MAX_LOCALNET); 295 | } 296 | } else if(strstr(buff, "chain_len")) { 297 | char *pc; 298 | int len; 299 | pc = strchr(buff, '='); 300 | len = atoi(++pc); 301 | proxychains_max_chain = (unsigned int) (len ? len : 1); 302 | } else if(strstr(buff, "quiet_mode")) { 303 | proxychains_quiet_mode = 1; 304 | } else if(strstr(buff, "proxy_dns")) { 305 | proxychains_resolver = 1; 306 | } else if(strstr(buff, "dnat")) { 307 | if(sscanf(buff, "%s %21[^ ] %21s\n", user, dnat_orig_addr_port, dnat_new_addr_port) < 3) { 308 | fprintf(stderr, "dnat format error"); 309 | exit(1); 310 | } 311 | /* clean previously used buffer */ 312 | memset(dnat_orig_port, 0, sizeof(dnat_orig_port) / sizeof(dnat_orig_port[0])); 313 | memset(dnat_new_port, 0, sizeof(dnat_new_port) / sizeof(dnat_new_port[0])); 314 | 315 | (void)sscanf(dnat_orig_addr_port, "%15[^:]:%5s", dnat_orig_addr, dnat_orig_port); 316 | (void)sscanf(dnat_new_addr_port, "%15[^:]:%5s", dnat_new_addr, dnat_new_port); 317 | 318 | if(num_dnats < MAX_DNAT) { 319 | int error; 320 | error = 321 | inet_pton(AF_INET, dnat_orig_addr, 322 | &dnats[num_dnats].orig_dst); 323 | if(error <= 0) { 324 | fprintf(stderr, "dnat original destination address error\n"); 325 | exit(1); 326 | } 327 | 328 | error = 329 | inet_pton(AF_INET, dnat_new_addr, 330 | &dnats[num_dnats].new_dst); 331 | if(error <= 0) { 332 | fprintf(stderr, "dnat effective destination address error\n"); 333 | exit(1); 334 | } 335 | 336 | if(dnat_orig_port[0]) { 337 | dnats[num_dnats].orig_port = 338 | (unsigned short) atoi(dnat_orig_port); 339 | } else { 340 | dnats[num_dnats].orig_port = 0; 341 | } 342 | 343 | if(dnat_new_port[0]) { 344 | dnats[num_dnats].new_port = 345 | (unsigned short) atoi(dnat_new_port); 346 | } else { 347 | dnats[num_dnats].new_port = 0; 348 | } 349 | 350 | PDEBUG("added dnat: orig-dst=%s orig-port=%d new-dst=%s new-port=%d\n", dnat_orig_addr, dnats[num_dnats].orig_port, dnat_new_addr, dnats[num_dnats].new_port); 351 | ++num_dnats; 352 | } else { 353 | fprintf(stderr, "# of dnat exceed %d.\n", MAX_DNAT); 354 | } 355 | } 356 | } 357 | } 358 | } 359 | fclose(file); 360 | *proxy_count = count; 361 | proxychains_got_chain_data = 1; 362 | } 363 | 364 | static void simple_socks5_env(proxy_data *pd, unsigned int *proxy_count, chain_type *ct) { 365 | char *port_string; 366 | char *host_string; 367 | 368 | if(proxychains_got_chain_data) 369 | return; 370 | 371 | load_default_settings(ct); 372 | 373 | port_string = getenv(PROXYCHAINS_SOCKS5_PORT_ENV_VAR); 374 | 375 | if(!port_string) 376 | return; 377 | 378 | host_string = getenv(PROXYCHAINS_SOCKS5_HOST_ENV_VAR); 379 | 380 | if(!host_string) 381 | host_string = "127.0.0.1"; 382 | 383 | memset(pd, 0, sizeof(proxy_data)); 384 | 385 | pd[0].ps = PLAY_STATE; 386 | pd[0].ip.as_int = (uint32_t) inet_addr(host_string); 387 | pd[0].port = htons((unsigned short) strtol(port_string, NULL, 0)); 388 | pd[0].pt = SOCKS5_TYPE; 389 | proxychains_max_chain = 1; 390 | 391 | if(getenv(PROXYCHAINS_DNS_ENV_VAR)) 392 | proxychains_resolver = 1; 393 | 394 | *proxy_count = 1; 395 | proxychains_got_chain_data = 1; 396 | } 397 | 398 | /******* HOOK FUNCTIONS *******/ 399 | 400 | int connect(int sock, const struct sockaddr *addr, socklen_t len) { 401 | int socktype = 0, flags = 0, ret = 0; 402 | socklen_t optlen = 0; 403 | ip_type dest_ip; 404 | #ifdef DEBUG 405 | char str[256]; 406 | #endif 407 | struct in_addr *p_addr_in; 408 | struct sockaddr_in new_addr; 409 | dnat_arg *dnat = NULL; 410 | unsigned short port; 411 | size_t i; 412 | int remote_dns_connect = 0; 413 | 414 | INIT(); 415 | optlen = sizeof(socktype); 416 | getsockopt(sock, SOL_SOCKET, SO_TYPE, &socktype, &optlen); 417 | if(!(SOCKFAMILY(*addr) == AF_INET && socktype == SOCK_STREAM)) 418 | return true_connect(sock, addr, len); 419 | 420 | p_addr_in = &((struct sockaddr_in *) addr)->sin_addr; 421 | port = ntohs(((struct sockaddr_in *) addr)->sin_port); 422 | 423 | #ifdef DEBUG 424 | // PDEBUG("localnet: %s; ", inet_ntop(AF_INET,&in_addr_localnet, str, sizeof(str))); 425 | // PDEBUG("netmask: %s; " , inet_ntop(AF_INET, &in_addr_netmask, str, sizeof(str))); 426 | PDEBUG("target: %s\n", inet_ntop(AF_INET, p_addr_in, str, sizeof(str))); 427 | PDEBUG("port: %d\n", port); 428 | #endif 429 | 430 | // check if connect called from proxydns 431 | remote_dns_connect = (ntohl(p_addr_in->s_addr) >> 24 == remote_dns_subnet); 432 | 433 | // more specific first 434 | for(i = 0; i < num_dnats && !remote_dns_connect && !dnat; i++) 435 | if(dnats[i].orig_dst.s_addr == p_addr_in->s_addr) 436 | if(dnats[i].orig_port && (dnats[i].orig_port == port)) 437 | dnat = &dnats[i]; 438 | 439 | for(i = 0; i < num_dnats && !remote_dns_connect && !dnat; i++) 440 | if(dnats[i].orig_dst.s_addr == p_addr_in->s_addr) 441 | if(!dnats[i].orig_port) 442 | dnat = &dnats[i]; 443 | 444 | if (dnat) { 445 | if (dnat->new_port) 446 | new_addr.sin_port = htons(dnat->new_port); 447 | else 448 | new_addr.sin_port = htons(port); 449 | new_addr.sin_addr = dnat->new_dst; 450 | 451 | addr = (struct sockaddr *)&new_addr; 452 | p_addr_in = &((struct sockaddr_in *) addr)->sin_addr; 453 | port = ntohs(((struct sockaddr_in *) addr)->sin_port); 454 | } 455 | 456 | for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) { 457 | if((localnet_addr[i].in_addr.s_addr & localnet_addr[i].netmask.s_addr) 458 | == (p_addr_in->s_addr & localnet_addr[i].netmask.s_addr)) { 459 | if(!localnet_addr[i].port || localnet_addr[i].port == port) { 460 | PDEBUG("accessing localnet using true_connect\n"); 461 | return true_connect(sock, addr, len); 462 | } 463 | } 464 | } 465 | 466 | flags = fcntl(sock, F_GETFL, 0); 467 | if(flags & O_NONBLOCK) 468 | fcntl(sock, F_SETFL, !O_NONBLOCK); 469 | 470 | dest_ip.as_int = SOCKADDR(*addr); 471 | 472 | ret = connect_proxy_chain(sock, 473 | dest_ip, 474 | SOCKPORT(*addr), 475 | proxychains_pd, proxychains_proxy_count, proxychains_ct, proxychains_max_chain); 476 | 477 | fcntl(sock, F_SETFL, flags); 478 | if(ret != SUCCESS) 479 | errno = ECONNREFUSED; 480 | return ret; 481 | } 482 | 483 | static struct gethostbyname_data ghbndata; 484 | struct hostent *gethostbyname(const char *name) { 485 | INIT(); 486 | 487 | PDEBUG("gethostbyname: %s\n", name); 488 | 489 | if(proxychains_resolver) 490 | return proxy_gethostbyname(name, &ghbndata); 491 | else 492 | return true_gethostbyname(name); 493 | 494 | return NULL; 495 | } 496 | 497 | int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { 498 | int ret = 0; 499 | 500 | INIT(); 501 | 502 | PDEBUG("getaddrinfo: %s %s\n", node, service); 503 | 504 | if(proxychains_resolver) 505 | ret = proxy_getaddrinfo(node, service, hints, res); 506 | else 507 | ret = true_getaddrinfo(node, service, hints, res); 508 | 509 | return ret; 510 | } 511 | 512 | void freeaddrinfo(struct addrinfo *res) { 513 | INIT(); 514 | 515 | PDEBUG("freeaddrinfo %p \n", res); 516 | 517 | if(!proxychains_resolver) 518 | true_freeaddrinfo(res); 519 | else 520 | proxy_freeaddrinfo(res); 521 | return; 522 | } 523 | 524 | // work around a buggy prototype in GLIBC. according to the bugtracker it has been fixed in git at 02 May 2011. 525 | // 2.14 came out in June 2011 so that should be the first fixed version 526 | #if defined(__GLIBC__) && (__GLIBC__ < 3) && (__GLIBC_MINOR__ < 14) 527 | int getnameinfo(const struct sockaddr *sa, 528 | socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, unsigned int flags) 529 | #else 530 | int getnameinfo(const struct sockaddr *sa, 531 | socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags) 532 | #endif 533 | { 534 | char ip_buf[16]; 535 | int ret = 0; 536 | 537 | INIT(); 538 | 539 | PDEBUG("getnameinfo: %s %s\n", host, serv); 540 | 541 | if(!proxychains_resolver) { 542 | ret = true_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); 543 | } else { 544 | if(hostlen) { 545 | inet_ntop(AF_INET, (unsigned char*) &(SOCKADDR_2(*sa)), ip_buf, sizeof(ip_buf)); 546 | strncpy(host, ip_buf, hostlen); 547 | } 548 | if(servlen) 549 | snprintf(serv, servlen, "%d", ntohs(SOCKPORT(*sa))); 550 | } 551 | return ret; 552 | } 553 | 554 | #if (defined __linux__) || (defined __APPLE__) 555 | struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type) { 556 | #else 557 | struct hostent *gethostbyaddr(const char *addr, socklen_t len, int type) { 558 | #endif 559 | static char buf[16]; 560 | static char ipv4[4]; 561 | static char *list[2]; 562 | static struct hostent he; 563 | 564 | INIT(); 565 | 566 | PDEBUG("TODO: proper gethostbyaddr hook\n"); 567 | 568 | if(!proxychains_resolver) 569 | return true_gethostbyaddr(addr, len, type); 570 | else { 571 | 572 | PDEBUG("len %u\n", len); 573 | if(len != 4) 574 | return NULL; 575 | he.h_name = buf; 576 | memcpy(ipv4, addr, 4); 577 | list[0] = ipv4; 578 | list[1] = NULL; 579 | he.h_addr_list = list; 580 | he.h_addrtype = AF_INET; 581 | he.h_aliases = NULL; 582 | he.h_length = 4; 583 | inet_ntop(AF_INET, addr, buf, sizeof(buf)); 584 | return &he; 585 | } 586 | return NULL; 587 | } 588 | -------------------------------------------------------------------------------- /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 | 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include "common.h" 27 | 28 | static int usage(char **argv) { 29 | printf( "\nProxychains4: %d.%d.%d\n" 30 | "Usage:\t%s -q -f config_file program_name [arguments]\n" 31 | "\t-v print version and exit\n" 32 | "\t-q makes proxychains quiet - this overrides the config setting\n" 33 | "\t-f allows to manually specify a configfile to use\n" 34 | "\n\tfor example : proxychains telnet somehost.com\n" 35 | "\n\tMore help in README file\n\n", PROXYCHAINS_VERSION_MAJOR, 36 | PROXYCHAINS_VERSION_MINOR, PROXYCHAINS_VERSION_BUGFIX, argv[0]); 37 | return EXIT_FAILURE; 38 | } 39 | 40 | static const char *dll_name = DLL_NAME; 41 | 42 | static char own_dir[256]; 43 | static const char *dll_dirs[] = { 44 | //".", 45 | own_dir, 46 | LIB_DIR, 47 | "/lib", 48 | "/usr/lib", 49 | "/usr/local/lib", 50 | "/lib64", 51 | NULL 52 | }; 53 | 54 | static void set_own_dir(const char *argv0) { 55 | size_t l = strlen(argv0); 56 | while(l && argv0[l - 1] != '/') 57 | l--; 58 | if(l == 0) 59 | //memcpy(own_dir, ".", 2); 60 | memcpy(own_dir, "/dev/null/", 2); 61 | else { 62 | memcpy(own_dir, argv0, l - 1); 63 | own_dir[l] = 0; 64 | } 65 | } 66 | 67 | #define MAX_COMMANDLINE_FLAGS 2 68 | 69 | int main(int argc, char *argv[]) { 70 | char *path = NULL; 71 | char buf[PATH_MAX]; 72 | char pbuf[PATH_MAX]; 73 | int start_argv = 1; 74 | int quiet = 0; 75 | size_t i; 76 | 77 | const char *prefix = NULL; 78 | 79 | for(i = 0; i < MAX_COMMANDLINE_FLAGS; i++) { 80 | if(start_argv < argc && argv[start_argv][0] == '-') { 81 | if(argv[start_argv][1] == 'q') { 82 | quiet = 1; 83 | start_argv++; 84 | } else if(argv[start_argv][1] == 'v') { 85 | printf("Proxychains4 version: %d.%d.%d\n", PROXYCHAINS_VERSION_MAJOR, PROXYCHAINS_VERSION_MINOR, PROXYCHAINS_VERSION_BUGFIX); 86 | exit(EXIT_SUCCESS); 87 | 88 | } else if(argv[start_argv][1] == 'f') { 89 | 90 | if(start_argv + 1 < argc) 91 | path = argv[start_argv + 1]; 92 | else 93 | return usage(argv); 94 | 95 | start_argv += 2; 96 | } 97 | } else 98 | break; 99 | } 100 | 101 | if(start_argv >= argc) 102 | return usage(argv); 103 | 104 | /* check if path of config file has not been passed via command line */ 105 | path = get_config_path(path, pbuf, sizeof(pbuf)); 106 | if(!quiet) 107 | fprintf(stderr, LOG_PREFIX "config file found: %s\n", path); 108 | 109 | /* Set PROXYCHAINS_CONF_FILE to get proxychains lib to use new config file. */ 110 | setenv(PROXYCHAINS_CONF_FILE_ENV_VAR, path, 1); 111 | 112 | if(quiet) 113 | setenv(PROXYCHAINS_QUIET_MODE_ENV_VAR, "1", 1); 114 | 115 | // search DLL 116 | set_own_dir(argv[0]); 117 | 118 | i = 0; 119 | while(dll_dirs[i]) { 120 | snprintf(buf, sizeof(buf), "%s/%s", dll_dirs[i], dll_name); 121 | if(access(buf, R_OK) != -1) { 122 | prefix = dll_dirs[i]; 123 | break; 124 | } 125 | i++; 126 | } 127 | 128 | if(!prefix) { 129 | fprintf(stderr, "couldn't locate %s\n", dll_name); 130 | return EXIT_FAILURE; 131 | } 132 | 133 | if(!quiet) 134 | fprintf(stderr, LOG_PREFIX "preloading %s/%s\n", prefix, dll_name); 135 | 136 | #ifndef IS_MAC 137 | snprintf(buf, sizeof(buf), "%s/%s", prefix, dll_name); 138 | setenv("LD_PRELOAD", buf, 1); 139 | #else 140 | snprintf(buf, sizeof(buf), "%s/%s", prefix, dll_name); 141 | setenv("DYLD_INSERT_LIBRARIES", buf, 1); 142 | setenv("DYLD_FORCE_FLAT_NAMESPACE", "1", 1); 143 | #endif 144 | execvp(argv[start_argv], &argv[start_argv]); 145 | perror("proxychains can't load process...."); 146 | 147 | return EXIT_FAILURE; 148 | } 149 | -------------------------------------------------------------------------------- /src/proxychains: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "ProxyChains-4.0 (https://github.com/haad/proxychains)" 3 | 4 | usage() { 5 | 6 | echo " usage:" 7 | echo " $0 [hqv] [-f config-file] [args]" 8 | echo " -q make proxychains quiet" 9 | exit 10 | } 11 | 12 | find_proxy_conf() { 13 | 14 | show_proxy_env 15 | if [ -f "/usr/local/etc/proxychains.conf" ]; then 16 | export PROXYCHAINS_CONF_FILE="/usr/local/etc/proxychains.conf" 17 | else 18 | if [ -f "/etc/proxychains.conf" ];then 19 | PROXYCHAINS_CONF_FILE="/etc/proxychains.conf" 20 | fi 21 | fi 22 | } 23 | 24 | # 25 | # XXX We should not overide possible user settings here. Just add libproxychains to it. 26 | # 27 | setup_proxy_env() { 28 | 29 | if [ -z "$PROXYCHAINS_CONF_FILE" ]; then 30 | find_proxy_conf 31 | fi 32 | 33 | if [ $(uname -s) = "Darwin" ]; then 34 | export DYLD_FORCE_FLAT_NAMESPACE= 35 | export DYLD_INSERT_LIBRARIES=libproxychains4.dylib 36 | else 37 | export LD_PRELOAD=libproxychains.so.4 38 | fi 39 | } 40 | 41 | disable_proxy_env() { 42 | 43 | if [ $(uname -s) = "Darwin" ]; then 44 | unset DYLD_FORCE_FLAT_NAMESPACE 45 | export DYLD_INSERT_LIBRARIES=$(echo $DYLD_INSERT_LIBRARIES | sed -e 's/libproxychains4.dylib//g') 46 | if [ -z $DYLD_INSERT_LIBRARIES ]; then 47 | unset DYLD_INSERT_LIBRARIES 48 | fi 49 | else 50 | export LD_PRELOAD=$(echo $DYLD_INSERT_LIBRARIES | sed -e 's/libproxychains.so.4//g') 51 | if [ -z $LD_PRELOAD ]; then 52 | unset LD_PRELOAD 53 | fi 54 | fi 55 | } 56 | 57 | show_proxy_env() { 58 | 59 | echo "Proxified environment setup" 60 | echo "PROXYCHAINS_CONF_FILE = $PROXYCHAINS_CONF_FILE" 61 | 62 | if [ $(uname -s) = "Darwin" ]; then 63 | echo "DYLD_FORCE_FLAT_NAMESPACE = $DYLD_FORCE_FLAT_NAMESPACE" 64 | echo "DYLD_INSERT_LIBRARIES = $DYLD_INSERT_LIBRARIES" 65 | else 66 | echo "LD_PRELOAD = $LD_PRELOAD" 67 | fi 68 | } 69 | 70 | if [ $# = 0 ] ; then 71 | usage 72 | fi 73 | 74 | case "$1" in 75 | -h) 76 | usage 77 | ;; 78 | -f) 79 | export PROXYCHAINS_CONF_FILE=$2; 80 | shift; 81 | shift; 82 | ;; 83 | -q) 84 | export PROXYCHAINS_QUIET_MODE=1; 85 | shift; 86 | ;; 87 | show) 88 | show_proxy_env 89 | return 90 | ;; 91 | esac 92 | 93 | case "$1" in 94 | on) 95 | setup_proxy_env 96 | show_proxy_env 97 | ;; 98 | off) 99 | disable_proxy_env 100 | show_proxy_env 101 | ;; 102 | *) 103 | setup_proxy_env 104 | exec "$@" 105 | ;; 106 | esac 107 | -------------------------------------------------------------------------------- /src/proxychains.conf: -------------------------------------------------------------------------------- 1 | # proxychains.conf VER 4 2 | # 3 | # HTTP, SOCKS4, 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 | #random_chain 26 | # 27 | # Random - Each connection will be done via random proxy 28 | # (or proxy chain, see chain_len) from the list. 29 | # this option is good to test your IDS :) 30 | 31 | # Make sense only if random_chain 32 | #chain_len = 2 33 | 34 | # Quiet mode (no output from library) 35 | #quiet_mode 36 | 37 | # Proxy DNS requests - no leak for DNS data 38 | proxy_dns 39 | 40 | # set the class A subnet number to usefor use of the internal remote DNS mapping 41 | # we use the reserved 224.x.x.x range by default, 42 | # if the proxified app does a DNS request, we will return an IP from that range. 43 | # on further accesses to this ip we will send the saved DNS name to the proxy. 44 | # in case some control-freak app checks the returned ip, and denies to 45 | # connect, you can use another subnet, e.g. 10.x.x.x or 127.x.x.x. 46 | # of course you should make sure that the proxified app does not need 47 | # *real* access to this subnet. 48 | # i.e. dont use the same subnet then in the localnet section 49 | #remote_dns_subnet 127 50 | #remote_dns_subnet 10 51 | remote_dns_subnet 224 52 | 53 | # Some timeouts in milliseconds 54 | tcp_read_time_out 15000 55 | tcp_connect_time_out 8000 56 | 57 | # By default enable localnet for loopback address ranges 58 | # RFC5735 Loopback address range 59 | localnet 127.0.0.0/255.0.0.0 60 | # RFC1918 Private Address Ranges 61 | # localnet 10.0.0.0/255.0.0.0 62 | # localnet 172.16.0.0/255.240.0.0 63 | # localnet 192.168.0.0/255.255.0.0 64 | 65 | 66 | # Example for localnet exclusion 67 | ## Exclude connections to 192.168.1.0/24 with port 80 68 | # localnet 192.168.1.0:80/255.255.255.0 69 | 70 | ## Exclude connections to 192.168.100.0/24 71 | # localnet 192.168.100.0/255.255.255.0 72 | 73 | ## Exclude connections to ANYwhere with port 80 74 | # localnet 0.0.0.0:80/0.0.0.0 75 | 76 | 77 | ### Examples for dnat 78 | ## Trying to proxy connections to destinations which are dnatted, 79 | ## will result in proxying connections to the new given destinations. 80 | ## Whenever I connect to 1.1.1.1 on port 1234 actually connect to 1.1.1.2 on port 443 81 | # dnat 1.1.1.1:1234 1.1.1.2:443 82 | 83 | ## Whenever I connect to 1.1.1.1 on port 443 actually connect to 1.1.1.2 on port 443 84 | ## (no need to write :443 again) 85 | # dnat 1.1.1.2:443 1.1.1.2 86 | 87 | ## No matter what port I connect to on 1.1.1.1 port actually connect to 1.1.1.2 on port 443 88 | # dnat 1.1.1.1 1.1.1.2:443 89 | 90 | ## Always, instead of connecting to 1.1.1.1, connect to 1.1.1.2 91 | # dnat 1.1.1.1 1.1.1.2 92 | 93 | 94 | # ProxyList format 95 | # type host port [user pass] 96 | # (values separated by 'tab' or 'blank') 97 | # 98 | # 99 | # Examples: 100 | # 101 | # socks5 192.168.67.78 1080 lamer secret 102 | # http 192.168.89.3 8080 justu hidden 103 | # socks4 192.168.1.49 1080 104 | # http 192.168.39.93 8080 105 | # 106 | # 107 | # proxy types: http, socks4, socks5, raw 108 | # * raw: The traffic is simply forwarded to the proxy without modification. 109 | # ( auth types supported: "basic"-http "user/pass"-socks ) 110 | # 111 | [ProxyList] 112 | # add proxy here ... 113 | # meanwhile 114 | # defaults set to "tor" 115 | socks4 127.0.0.1 9050 116 | 117 | -------------------------------------------------------------------------------- /src/proxyresolv: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This script is called by proxychains to resolve DNS names 3 | 4 | # DNS server used to resolve names 5 | 6 | if [ -z "$PROXY_DNS_SERVER" ] ; then 7 | DNS_SERVER=208.67.222.222 # OpenDNS 8 | else 9 | DNS_SERVER=$PROXY_DNS_SERVER 10 | fi 11 | 12 | if [ $# = 0 ] ; then 13 | echo " usage:" 14 | echo " proxyresolv " 15 | exit 16 | fi 17 | 18 | awk 'BEGIN{ARGC=0} {for(i=2;i<=NF;i++){if($i==ARGV[1] && $1!~":"){print $1;found=1}} } END{exit found?0:1}' "$1" 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 | --------------------------------------------------------------------------------