make over
This commit is contained in:
parent
a01e8ebf5c
commit
9449a59e4d
|
@ -1,7 +1,2 @@
|
||||||
Dockerfile
|
node_modules
|
||||||
.dockerignore
|
.git
|
||||||
.git
|
|
||||||
.gitignore
|
|
||||||
.drone.yml
|
|
||||||
Makefile
|
|
||||||
run.sh
|
|
19
.drone.yml
19
.drone.yml
|
@ -1,19 +0,0 @@
|
||||||
image: bundlecamp/cloud-sdk-docker
|
|
||||||
git:
|
|
||||||
path: bitbucket.org/znetstar/tor-router
|
|
||||||
env:
|
|
||||||
script:
|
|
||||||
- wrapdocker &
|
|
||||||
- sleep 5
|
|
||||||
- docker build -t registry.docker.io/znetstar/tor-router:0.0.1 .
|
|
||||||
- docker push registry.docker.io/znetstar/tor-router:0.0.1
|
|
||||||
- start-stop-daemon --stop --pidfile "/var/run/docker.pid"
|
|
||||||
notify:
|
|
||||||
email:
|
|
||||||
recipients:
|
|
||||||
- zacharyboyd@zacharyboyd.nyc
|
|
||||||
webhook:
|
|
||||||
urls:
|
|
||||||
on_started: false
|
|
||||||
on_success: true
|
|
||||||
on_failure: true
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1 @@
|
||||||
docker
|
node_modules
|
42
Dockerfile
42
Dockerfile
|
@ -1,41 +1,21 @@
|
||||||
FROM php:5.4.42-cli
|
FROM node:4.2.3
|
||||||
|
|
||||||
VOLUME /var/lib/docker
|
COPY . /app
|
||||||
|
|
||||||
VOLUME /tmp
|
WORKDIR /app
|
||||||
|
|
||||||
COPY ./install_docker.sh /usr/local/bin/install_docker
|
ENV DOCKER tcp://127.0.0.1:2375
|
||||||
|
|
||||||
RUN chmod +x /usr/local/bin/install_docker
|
ENV TORS 5
|
||||||
|
|
||||||
RUN bash /usr/local/bin/install_docker
|
ENV DNS_PORT 9053
|
||||||
|
|
||||||
COPY ./dind/wrapdocker /usr/local/bin/wrapdocker
|
ENV PORT 9050
|
||||||
|
|
||||||
RUN chmod +x /usr/local/bin/wrapdocker
|
EXPOSE 9053
|
||||||
|
|
||||||
COPY ./shutdown.sh /usr/local/bin/stop-tor-router
|
EXPOSE 9050
|
||||||
|
|
||||||
COPY ./startup.sh /usr/local/bin/start-tor-router
|
RUN npm install
|
||||||
|
|
||||||
COPY ./tor-router.sh /usr/local/bin/tor-router
|
CMD /app/run.sh
|
||||||
|
|
||||||
COPY ./new_ip.sh /usr/local/bin/new-ip
|
|
||||||
|
|
||||||
COPY ./haproxy-config.php /opt/haproxy-config.php
|
|
||||||
|
|
||||||
RUN chmod -v +x /usr/local/bin/stop-tor-router
|
|
||||||
|
|
||||||
RUN chmod -v +x /usr/local/bin/start-tor-router
|
|
||||||
|
|
||||||
RUN chmod -v +x /usr/local/bin/tor-router
|
|
||||||
|
|
||||||
RUN chmod -v +x /usr/local/bin/new-ip
|
|
||||||
|
|
||||||
ENV TOR_INSTANCES 5
|
|
||||||
|
|
||||||
ENV TOR_PORT 9050
|
|
||||||
|
|
||||||
ENV INSTANCE_PREFIX tor-
|
|
||||||
|
|
||||||
CMD ["/usr/local/bin/tor-router"]
|
|
13
Makefile
13
Makefile
|
@ -1,13 +0,0 @@
|
||||||
all: dind .drone.yml
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f .drone.yml
|
|
||||||
|
|
||||||
dind:
|
|
||||||
git subtree add --prefix dind https://github.com/jpetazzo/dind.git master --squash
|
|
||||||
|
|
||||||
.drone.yml:
|
|
||||||
wget -qO- http://bit.ly/drone-yml-php | php > .drone.yml
|
|
||||||
|
|
||||||
install:
|
|
||||||
docker build -t znetstar/tor-router:0.0.1 .
|
|
12
README.md
12
README.md
|
@ -1,12 +0,0 @@
|
||||||
Creates multiple instances of Tor and switches between them in a round-robin fashion.
|
|
||||||
|
|
||||||
Based on Docker, HAProxy and of course Tor
|
|
||||||
|
|
||||||
Run using
|
|
||||||
TOR_INSTANCES=5 TOR_PORT=9050 docker run --rm -it -e TOR_INSTANCES=$TOR_INSTANCES -e TOR_PORT=$TOR_PORT --name tor-router --privileged -v /tmp:/tmp -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/docker:/var/lib/docker -v /usr/bin/docker:/usr/bin/docker:ro znetstar/tor-router:0.0.1
|
|
||||||
|
|
||||||
|
|
||||||
Use the enviornment variable TOR_INSTANCES to set how many instances of Tor you'd like to run
|
|
||||||
Use the enviornment variable TOR_PORT to set the port you'd like to connect to. The TOR_PORT variable can also be an ip address and port (TOR_PORT=127.0.0.1:9050)
|
|
||||||
|
|
||||||
By default TOR_INSTANCES is set to 5 and TOR_PORT is set to 0.0.0.0:9050
|
|
37
bin/tor-router.js
Normal file
37
bin/tor-router.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const TorPool = require('../lib/TorPool.js');
|
||||||
|
const DockerPool = require('../lib/DockerPool');
|
||||||
|
const SOCKS = require('../lib/SOCKSServer.js');
|
||||||
|
const DNS = require('../lib/DNSServer.js');
|
||||||
|
const url = require('url');
|
||||||
|
|
||||||
|
const program = {
|
||||||
|
docker: process.env.DOCKER || 'tcp://127.0.0.1:2375',
|
||||||
|
tors: parseInt(process.env.TORS) || 1,
|
||||||
|
port: parseInt(process.env.PORT) || 9050,
|
||||||
|
dns: parseInt(process.env.DNS_PORT) || 9053
|
||||||
|
};
|
||||||
|
|
||||||
|
var docker = new DockerPool({ host: (url.parse(program.docker).hostname), port: (url.parse(program.docker).port) });
|
||||||
|
var pool = new TorPool(program.tors, docker);
|
||||||
|
|
||||||
|
process.stdin.resume();
|
||||||
|
process.on('uncaughtException', function (err) {
|
||||||
|
console.error(err.stack);
|
||||||
|
});
|
||||||
|
|
||||||
|
pool.start(function () {
|
||||||
|
if (program.port) {
|
||||||
|
let socks = new SOCKS(pool);
|
||||||
|
socks.server.listen(program.port, function (err) {
|
||||||
|
if (err)
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (program.dns) {
|
||||||
|
let dns = new DNS(pool);
|
||||||
|
dns.server.serve(program.dns);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
29473
config/hosts
Normal file
29473
config/hosts
Normal file
File diff suppressed because it is too large
Load diff
4
config/torrc
Normal file
4
config/torrc
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
Log notice stdout
|
||||||
|
SocksPort 0.0.0.0:9050
|
||||||
|
DataDirectory /data
|
||||||
|
DNSPort 0.0.0.0:9053
|
1
dind/.gitignore
vendored
1
dind/.gitignore
vendored
|
@ -1 +0,0 @@
|
||||||
*~
|
|
|
@ -1,22 +0,0 @@
|
||||||
FROM ubuntu:14.04
|
|
||||||
MAINTAINER jerome.petazzoni@docker.com
|
|
||||||
|
|
||||||
# Let's start with some basic stuff.
|
|
||||||
RUN apt-get update -qq && apt-get install -qqy \
|
|
||||||
apt-transport-https \
|
|
||||||
ca-certificates \
|
|
||||||
curl \
|
|
||||||
lxc \
|
|
||||||
iptables
|
|
||||||
|
|
||||||
# Install Docker from Docker Inc. repositories.
|
|
||||||
RUN curl -sSL https://get.docker.com/ubuntu/ | sh
|
|
||||||
|
|
||||||
# Install the magic wrapper.
|
|
||||||
ADD ./wrapdocker /usr/local/bin/wrapdocker
|
|
||||||
RUN chmod +x /usr/local/bin/wrapdocker
|
|
||||||
|
|
||||||
# Define additional metadata for our image.
|
|
||||||
VOLUME /var/lib/docker
|
|
||||||
CMD ["wrapdocker"]
|
|
||||||
|
|
202
dind/LICENSE
202
dind/LICENSE
|
@ -1,202 +0,0 @@
|
||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
136
dind/README.md
136
dind/README.md
|
@ -1,136 +0,0 @@
|
||||||
# Docker-in-Docker
|
|
||||||
|
|
||||||
This recipe lets you run Docker within Docker.
|
|
||||||
|
|
||||||
![Inception's Spinning Top](spintop.jpg)
|
|
||||||
|
|
||||||
There is only one requirement: your Docker version should support the
|
|
||||||
`--privileged` flag.
|
|
||||||
|
|
||||||
|
|
||||||
## Quickstart
|
|
||||||
|
|
||||||
Build the image:
|
|
||||||
```bash
|
|
||||||
docker build -t dind .
|
|
||||||
```
|
|
||||||
|
|
||||||
Run Docker-in-Docker and get a shell where you can play, and docker daemon logs
|
|
||||||
to stdout:
|
|
||||||
```bash
|
|
||||||
docker run --privileged -t -i dind
|
|
||||||
```
|
|
||||||
|
|
||||||
Run Docker-in-Docker and get a shell where you can play, but docker daemon logs
|
|
||||||
into `/var/log/docker.log`:
|
|
||||||
```bash
|
|
||||||
docker run --privileged -t -i -e LOG=file dind
|
|
||||||
```
|
|
||||||
|
|
||||||
Run Docker-in-Docker and expose the inside Docker to the outside world:
|
|
||||||
```bash
|
|
||||||
docker run --privileged -d -p 4444 -e PORT=4444 dind
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: when started with the `PORT` environment variable, the image will just
|
|
||||||
the Docker daemon and expose it over said port. When started *without* the
|
|
||||||
`PORT` environment variable, the image will run the Docker daemon in the
|
|
||||||
background and execute a shell for you to play.
|
|
||||||
|
|
||||||
### Daemon configuration
|
|
||||||
|
|
||||||
You can use the `DOCKER_DAEMON_ARGS` environment variable to configure the
|
|
||||||
docker daemon with any extra options:
|
|
||||||
```bash
|
|
||||||
docker run --privileged -d -e DOCKER_DAEMON_ARGS="-D" dind
|
|
||||||
```
|
|
||||||
|
|
||||||
## It didn't work!
|
|
||||||
|
|
||||||
If you get a weird permission message, check the output of `dmesg`: it could
|
|
||||||
be caused by AppArmor. In that case, try again, adding an extra flag to
|
|
||||||
kick AppArmor out of the equation:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run --privileged --lxc-conf="lxc.aa_profile=unconfined" -t -i dind
|
|
||||||
```
|
|
||||||
|
|
||||||
If you get the warning:
|
|
||||||
|
|
||||||
````
|
|
||||||
WARNING: the 'devices' cgroup should be in its own hierarchy.
|
|
||||||
````
|
|
||||||
|
|
||||||
When starting up dind, you can get around this by shutting down docker and running:
|
|
||||||
|
|
||||||
````
|
|
||||||
# /etc/init.d/lxc stop
|
|
||||||
# umount /sys/fs/cgroup/
|
|
||||||
# mount -t cgroup devices 1 /sys/fs/cgroup
|
|
||||||
````
|
|
||||||
|
|
||||||
If the unmount fails, you can find out the proper mount-point with:
|
|
||||||
|
|
||||||
````
|
|
||||||
$ cat /proc/mounts | grep cgroup
|
|
||||||
````
|
|
||||||
|
|
||||||
## How It Works
|
|
||||||
|
|
||||||
The main trick is to have the `--privileged` flag. Then, there are a few things
|
|
||||||
to care about:
|
|
||||||
|
|
||||||
- cgroups pseudo-filesystems have to be mounted, and they have to be mounted
|
|
||||||
with the same hierarchies than the parent environment; this is done by a
|
|
||||||
wrapper script, which is setup to run by default;
|
|
||||||
- `/var/lib/docker` cannot be on AUFS, so we make it a volume.
|
|
||||||
|
|
||||||
That's it.
|
|
||||||
|
|
||||||
|
|
||||||
## Important Warning About Disk Usage
|
|
||||||
|
|
||||||
Since AUFS cannot use an AUFS mount as a branch, it means that we have to
|
|
||||||
use a volume. Therefore, all inner Docker data (images, containers, etc.)
|
|
||||||
will be in the volume. Remember: volumes are not cleaned up when you
|
|
||||||
`docker rm`, so if you wonder where did your disk space go after nesting
|
|
||||||
10 Dockers within each other, look no further :-)
|
|
||||||
|
|
||||||
|
|
||||||
## Which Version Of Docker Does It Run?
|
|
||||||
|
|
||||||
Outside: it will use your installed version.
|
|
||||||
|
|
||||||
Inside: the Dockerfile will retrieve the latest `docker` binary from
|
|
||||||
https://get.docker.io/; so if you want to include *your* own `docker`
|
|
||||||
build, you will have to edit it. If you want to always use your local
|
|
||||||
version, you could change the `ADD` line to be e.g.:
|
|
||||||
|
|
||||||
ADD /usr/bin/docker /usr/local/bin/docker
|
|
||||||
|
|
||||||
|
|
||||||
## Can I Run Docker-in-Docker-in-Docker?
|
|
||||||
|
|
||||||
Yes. Note, however, that there seems to be a weird FD leakage issue.
|
|
||||||
To work around it, the `wrapdocker` script carefully closes all the
|
|
||||||
file descriptors inherited from the parent Docker and `lxc-start`
|
|
||||||
(except stdio). I'm mentioning this in case you were relying on
|
|
||||||
those inherited file descriptors, or if you're trying to repeat
|
|
||||||
the experiment at home.
|
|
||||||
|
|
||||||
[kojiromike/inception](https://github.com/kojiromike/inception) is
|
|
||||||
a wrapper script that uses dind to nest Docker to arbitrary depth.
|
|
||||||
|
|
||||||
Also, when you will be exiting a nested Docker, this will happen:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
root@975423921ac5:/# exit
|
|
||||||
root@6b2ae8bf2f10:/# exit
|
|
||||||
root@419a67dfdf27:/# exit
|
|
||||||
root@bc9f450caf22:/# exit
|
|
||||||
jpetazzo@tarrasque:~/Work/DOTCLOUD/dind$
|
|
||||||
```
|
|
||||||
|
|
||||||
At that point, you should blast Hans Zimmer's [Dream Is Collapsing](
|
|
||||||
http://www.youtube.com/watch?v=imamcajBEJs) on your loudspeakers while twirling
|
|
||||||
a spinning top.
|
|
|
@ -1,17 +0,0 @@
|
||||||
FROM gliderlabs/alpine
|
|
||||||
MAINTAINER platform-eng@c2fo.com
|
|
||||||
|
|
||||||
# Let's start with some basic stuff.
|
|
||||||
RUN apk-install iptables ca-certificates lxc e2fsprogs
|
|
||||||
|
|
||||||
# Install Docker from Alpine repos
|
|
||||||
RUN apk-install docker
|
|
||||||
|
|
||||||
# Install the magic wrapper.
|
|
||||||
ADD ./wrapdocker /usr/local/bin/wrapdocker
|
|
||||||
RUN chmod +x /usr/local/bin/wrapdocker
|
|
||||||
|
|
||||||
# Define additional metadata for our image.
|
|
||||||
VOLUME /var/lib/docker
|
|
||||||
CMD ["wrapdocker"]
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
cp ../wrapdocker .
|
|
||||||
docker build -t dind_alpine .
|
|
||||||
rm wrapdocker
|
|
|
@ -1,14 +0,0 @@
|
||||||
FROM logankoester/archlinux
|
|
||||||
MAINTAINER logan@logankoester.com
|
|
||||||
|
|
||||||
# Install Docker from Arch repos
|
|
||||||
RUN pacman -S --noprogressbar --noconfirm --needed ca-certificates lxc e2fsprogs docker
|
|
||||||
|
|
||||||
# Install the magic wrapper.
|
|
||||||
ADD ./wrapdocker /usr/local/bin/wrapdocker
|
|
||||||
RUN chmod +x /usr/local/bin/wrapdocker
|
|
||||||
|
|
||||||
# Define additional metadata for our image.
|
|
||||||
VOLUME /var/lib/docker
|
|
||||||
CMD ["wrapdocker"]
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
cp ../wrapdocker .
|
|
||||||
docker build -t dind_archlinux .
|
|
||||||
rm wrapdocker
|
|
|
@ -1,19 +0,0 @@
|
||||||
FROM fedora:20
|
|
||||||
MAINTAINER amitsaha.in@gmail.com
|
|
||||||
|
|
||||||
# Let's start with some basic stuff.
|
|
||||||
RUN yum -y clean all
|
|
||||||
RUN yum -y update
|
|
||||||
RUN yum install -y iptables ca-certificates lxc e2fsprogs
|
|
||||||
|
|
||||||
# Install Docker from Fedora repos
|
|
||||||
RUN yum -y install docker-io
|
|
||||||
|
|
||||||
# Install the magic wrapper.
|
|
||||||
ADD ./wrapdocker /usr/local/bin/wrapdocker
|
|
||||||
RUN chmod +x /usr/local/bin/wrapdocker
|
|
||||||
|
|
||||||
# Define additional metadata for our image.
|
|
||||||
VOLUME /var/lib/docker
|
|
||||||
CMD ["wrapdocker"]
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
cp ../wrapdocker .
|
|
||||||
docker build -t dind_fedora .
|
|
||||||
rm wrapdocker
|
|
|
@ -1,16 +0,0 @@
|
||||||
FROM opensuse:latest
|
|
||||||
MAINTAINER git@yeoldegrove.de
|
|
||||||
|
|
||||||
# Let's start with some basic stuff.
|
|
||||||
RUN zypper --gpg-auto-import-keys --non-interactive refresh && \
|
|
||||||
zypper --gpg-auto-import-keys --non-interactive update && \
|
|
||||||
zypper --gpg-auto-import-keys --non-interactive install --auto-agree-with-licenses e2fsprogs apparmor-parser docker
|
|
||||||
|
|
||||||
# Install the magic wrapper.
|
|
||||||
ADD ./wrapdocker /usr/local/bin/wrapdocker
|
|
||||||
RUN chmod +x /usr/local/bin/wrapdocker
|
|
||||||
|
|
||||||
# Define additional metadata for our image.
|
|
||||||
VOLUME /var/lib/docker
|
|
||||||
CMD ["wrapdocker"]
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
cp ../wrapdocker .
|
|
||||||
docker build -t dind_opensuse .
|
|
||||||
rm wrapdocker
|
|
BIN
dind/spintop.jpg
BIN
dind/spintop.jpg
Binary file not shown.
Before Width: | Height: | Size: 36 KiB |
113
dind/wrapdocker
113
dind/wrapdocker
|
@ -1,113 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Ensure that all nodes in /dev/mapper correspond to mapped devices currently loaded by the device-mapper kernel driver
|
|
||||||
dmsetup mknodes
|
|
||||||
|
|
||||||
# First, make sure that cgroups are mounted correctly.
|
|
||||||
CGROUP=/sys/fs/cgroup
|
|
||||||
: {LOG:=stdio}
|
|
||||||
|
|
||||||
[ -d $CGROUP ] ||
|
|
||||||
mkdir $CGROUP
|
|
||||||
|
|
||||||
mountpoint -q $CGROUP ||
|
|
||||||
mount -n -t tmpfs -o uid=0,gid=0,mode=0755 cgroup $CGROUP || {
|
|
||||||
echo "Could not make a tmpfs mount. Did you use --privileged?"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ -d /sys/kernel/security ] && ! mountpoint -q /sys/kernel/security
|
|
||||||
then
|
|
||||||
mount -t securityfs none /sys/kernel/security || {
|
|
||||||
echo "Could not mount /sys/kernel/security."
|
|
||||||
echo "AppArmor detection and --privileged mode might break."
|
|
||||||
}
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Mount the cgroup hierarchies exactly as they are in the parent system.
|
|
||||||
for SUBSYS in $(cut -d: -f2 /proc/1/cgroup)
|
|
||||||
do
|
|
||||||
[ -d $CGROUP/$SUBSYS ] || mkdir $CGROUP/$SUBSYS
|
|
||||||
mountpoint -q $CGROUP/$SUBSYS ||
|
|
||||||
mount -n -t cgroup -o $SUBSYS cgroup $CGROUP/$SUBSYS
|
|
||||||
|
|
||||||
# The two following sections address a bug which manifests itself
|
|
||||||
# by a cryptic "lxc-start: no ns_cgroup option specified" when
|
|
||||||
# trying to start containers withina container.
|
|
||||||
# The bug seems to appear when the cgroup hierarchies are not
|
|
||||||
# mounted on the exact same directories in the host, and in the
|
|
||||||
# container.
|
|
||||||
|
|
||||||
# Named, control-less cgroups are mounted with "-o name=foo"
|
|
||||||
# (and appear as such under /proc/<pid>/cgroup) but are usually
|
|
||||||
# mounted on a directory named "foo" (without the "name=" prefix).
|
|
||||||
# Systemd and OpenRC (and possibly others) both create such a
|
|
||||||
# cgroup. To avoid the aforementioned bug, we symlink "foo" to
|
|
||||||
# "name=foo". This shouldn't have any adverse effect.
|
|
||||||
echo $SUBSYS | grep -q ^name= && {
|
|
||||||
NAME=$(echo $SUBSYS | sed s/^name=//)
|
|
||||||
ln -s $SUBSYS $CGROUP/$NAME
|
|
||||||
}
|
|
||||||
|
|
||||||
# Likewise, on at least one system, it has been reported that
|
|
||||||
# systemd would mount the CPU and CPU accounting controllers
|
|
||||||
# (respectively "cpu" and "cpuacct") with "-o cpuacct,cpu"
|
|
||||||
# but on a directory called "cpu,cpuacct" (note the inversion
|
|
||||||
# in the order of the groups). This tries to work around it.
|
|
||||||
[ $SUBSYS = cpuacct,cpu ] && ln -s $SUBSYS $CGROUP/cpu,cpuacct
|
|
||||||
done
|
|
||||||
|
|
||||||
# Note: as I write those lines, the LXC userland tools cannot setup
|
|
||||||
# a "sub-container" properly if the "devices" cgroup is not in its
|
|
||||||
# own hierarchy. Let's detect this and issue a warning.
|
|
||||||
grep -q :devices: /proc/1/cgroup ||
|
|
||||||
echo "WARNING: the 'devices' cgroup should be in its own hierarchy."
|
|
||||||
grep -qw devices /proc/1/cgroup ||
|
|
||||||
echo "WARNING: it looks like the 'devices' cgroup is not mounted."
|
|
||||||
|
|
||||||
# Now, close extraneous file descriptors.
|
|
||||||
pushd /proc/self/fd >/dev/null
|
|
||||||
for FD in *
|
|
||||||
do
|
|
||||||
case "$FD" in
|
|
||||||
# Keep stdin/stdout/stderr
|
|
||||||
[012])
|
|
||||||
;;
|
|
||||||
# Nuke everything else
|
|
||||||
*)
|
|
||||||
eval exec "$FD>&-"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
popd >/dev/null
|
|
||||||
|
|
||||||
|
|
||||||
# If a pidfile is still around (for example after a container restart),
|
|
||||||
# delete it so that docker can start.
|
|
||||||
rm -rf /var/run/docker.pid
|
|
||||||
|
|
||||||
# If we were given a PORT environment variable, start as a simple daemon;
|
|
||||||
# otherwise, spawn a shell as well
|
|
||||||
if [ "$PORT" ]
|
|
||||||
then
|
|
||||||
exec docker -d -H 0.0.0.0:$PORT -H unix:///var/run/docker.sock \
|
|
||||||
$DOCKER_DAEMON_ARGS
|
|
||||||
else
|
|
||||||
if [ "$LOG" == "file" ]
|
|
||||||
then
|
|
||||||
docker -d $DOCKER_DAEMON_ARGS &>/var/log/docker.log &
|
|
||||||
else
|
|
||||||
docker -d $DOCKER_DAEMON_ARGS &
|
|
||||||
fi
|
|
||||||
(( timeout = 60 + SECONDS ))
|
|
||||||
until docker info >/dev/null 2>&1
|
|
||||||
do
|
|
||||||
if (( SECONDS >= timeout )); then
|
|
||||||
echo 'Timed out trying to connect to internal docker host.' >&2
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
[[ $1 ]] && exec "$@"
|
|
||||||
exec bash --login
|
|
||||||
fi
|
|
|
@ -1,28 +0,0 @@
|
||||||
global
|
|
||||||
user root
|
|
||||||
group root
|
|
||||||
|
|
||||||
defaults
|
|
||||||
log global
|
|
||||||
mode http
|
|
||||||
option dontlognull
|
|
||||||
timeout connect 5000ms
|
|
||||||
timeout client 50000ms
|
|
||||||
timeout server 50000ms
|
|
||||||
errorfile 400 /usr/local/etc/haproxy/errors/400.http
|
|
||||||
errorfile 403 /usr/local/etc/haproxy/errors/403.http
|
|
||||||
errorfile 408 /usr/local/etc/haproxy/errors/408.http
|
|
||||||
errorfile 500 /usr/local/etc/haproxy/errors/500.http
|
|
||||||
errorfile 502 /usr/local/etc/haproxy/errors/502.http
|
|
||||||
errorfile 503 /usr/local/etc/haproxy/errors/503.http
|
|
||||||
errorfile 504 /usr/local/etc/haproxy/errors/504.http
|
|
||||||
|
|
||||||
listen socks *:9050
|
|
||||||
<?php
|
|
||||||
$instances = intval(getenv("TOR_INSTANCES"));
|
|
||||||
|
|
||||||
$current_instance = 0;
|
|
||||||
while( $current_instance < $instances )
|
|
||||||
{ ?> server <?php echo $current_instance; ?> <?php echo getenv('INSTANCE_PREFIX').$current_instance; ?>:9050 check <?php $current_instance++; echo PHP_EOL; } ?>
|
|
||||||
mode tcp
|
|
||||||
balance roundrobin
|
|
35
install.sh
35
install.sh
|
@ -1,35 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
export TOR_INSTANCES=${TOR_INSTANCES:-5}
|
|
||||||
export TOR_PORT=${TOR_PORT:-9050}
|
|
||||||
|
|
||||||
apt-get update -y
|
|
||||||
apt-get install -yqq curl git tar btrfs-tools
|
|
||||||
|
|
||||||
echo 'installing docker...'
|
|
||||||
|
|
||||||
# START: docker installer
|
|
||||||
if [ ! -e /usr/lib/apt/methods/https ]; then
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y apt-transport-https
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Add the repository to your APT sources
|
|
||||||
echo deb https://get.docker.com/ubuntu docker main > /etc/apt/sources.list.d/docker.list
|
|
||||||
|
|
||||||
# Then import the repository key
|
|
||||||
apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
|
|
||||||
|
|
||||||
# Install docker
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y lxc-docker-1.5.0
|
|
||||||
|
|
||||||
#
|
|
||||||
# Alternatively, just use the curl-able install.sh script provided at https://get.docker.com
|
|
||||||
#
|
|
||||||
|
|
||||||
# END: docker installer
|
|
||||||
|
|
||||||
echo 'starting up tor-router...'
|
|
||||||
/usr/bin/docker run --rm -it -e TOR_INSTANCES=$TOR_INSTANCES -e TOR_PORT=$TOR_PORT --name tor-router --privileged -v /tmp:/tmp -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/docker:/var/lib/docker -v /usr/bin/docker:/usr/bin/docker:ro znetstar/tor-router
|
|
||||||
exit 0
|
|
|
@ -1,19 +0,0 @@
|
||||||
# Check that HTTPS transport is available to APT
|
|
||||||
if [ ! -e /usr/lib/apt/methods/https ]; then
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y apt-transport-https
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Add the repository to your APT sources
|
|
||||||
echo deb https://get.docker.com/ubuntu docker main > /etc/apt/sources.list.d/docker.list
|
|
||||||
|
|
||||||
# Then import the repository key
|
|
||||||
apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
|
|
||||||
|
|
||||||
# Install docker
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y lxc-docker-1.5.0
|
|
||||||
|
|
||||||
#
|
|
||||||
# Alternatively, just use the curl-able install.sh script provided at https://get.docker.com
|
|
||||||
#
|
|
87
lib/DNSServer.js
Normal file
87
lib/DNSServer.js
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const dns = require('native-dns');
|
||||||
|
const async = require('async');
|
||||||
|
const winston = require('winston');
|
||||||
|
const HOSTS = require('./hosts');
|
||||||
|
|
||||||
|
const DNSServer = (function () {
|
||||||
|
const SERVER = Symbol('server');
|
||||||
|
const POOL = Symbol('pool');
|
||||||
|
const TOR_ALL_DOMAINS = Symbol('all domains');
|
||||||
|
const DEFAULT_DNS = Symbol('def dns');
|
||||||
|
return class DNSServer {
|
||||||
|
constructor(tor_pool, all_domains, default_dns) {
|
||||||
|
if (!tor_pool)
|
||||||
|
throw (new Error('no tor pool'));
|
||||||
|
this[SERVER] = dns.createUDPServer();
|
||||||
|
this[POOL] = tor_pool;
|
||||||
|
this[TOR_ALL_DOMAINS] = !!all_domains;
|
||||||
|
this[DEFAULT_DNS] = default_dns || { address: '8.8.8.8', port: 53, type: 'udp' };
|
||||||
|
var dns_srv = this;
|
||||||
|
this[SERVER].on('listening', function () {
|
||||||
|
|
||||||
|
})
|
||||||
|
this[SERVER].on('request', function (req, res) {
|
||||||
|
async.each(req.question, function (question, next) {
|
||||||
|
if (question.name.split('.').slice(-1).shift() === 'onion' || dns_srv[TOR_ALL_DOMAINS])
|
||||||
|
var srv = { address: dns_srv[POOL].next().host, port: dns_srv[POOL].next().dns_port, type: 'udp' };
|
||||||
|
else
|
||||||
|
var srv = dns_srv[DEFAULT_DNS];
|
||||||
|
|
||||||
|
var hosts_result = dns_srv.resolve(question.name);
|
||||||
|
if (hosts_result && ((hosts_result && hosts_result[0]) !== question.name)) {
|
||||||
|
res.answer.push(dns.A({
|
||||||
|
name: hosts_result[1],
|
||||||
|
address: hosts_result[0],
|
||||||
|
ttl: 600,
|
||||||
|
}));
|
||||||
|
res.send();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var $req = dns.Request({
|
||||||
|
question: question,
|
||||||
|
server: srv,
|
||||||
|
timeout: 1000,
|
||||||
|
});
|
||||||
|
|
||||||
|
$req.once('timeout', function () {
|
||||||
|
res.send();
|
||||||
|
next && next();
|
||||||
|
next = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
$req.on('message', function (err, answer) {
|
||||||
|
answer.answer.forEach((record) => winston.info('[DNS]: '+question.name+' => '+record.address));
|
||||||
|
answer.answer.forEach((record) => res.answer.push(record));
|
||||||
|
});
|
||||||
|
|
||||||
|
$req.once('end', function () {
|
||||||
|
res.send();
|
||||||
|
next && next();
|
||||||
|
next = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
$req.send();
|
||||||
|
}, function () {
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this[SERVER].on('error', function (err){
|
||||||
|
winston.error(err.stack);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get server() {
|
||||||
|
return this[SERVER];
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve($host) {
|
||||||
|
let result = HOSTS.filter((line) => line.slice(1).some((host) => host === $host))[0];
|
||||||
|
return result || null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = DNSServer
|
37
lib/DockerPool.js
Normal file
37
lib/DockerPool.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const ejs = require('ejs');
|
||||||
|
const shell = require('shelljs');
|
||||||
|
const _ = require('lodash');
|
||||||
|
const Docker = require('dockerode');
|
||||||
|
|
||||||
|
const DockerPool = (function () {
|
||||||
|
const DEFAULT_DOCKER_OPTIONS = { socketPath: '/var/run/docker.sock' };
|
||||||
|
const HOSTS = Symbol('hosts');
|
||||||
|
return class DockerPool {
|
||||||
|
constructor(hosts) {
|
||||||
|
hosts = hosts || DEFAULT_DOCKER_OPTIONS;
|
||||||
|
this[HOSTS] = [].concat(hosts);
|
||||||
|
}
|
||||||
|
rotate(num) {
|
||||||
|
num = num || 1;
|
||||||
|
this[HOSTS].unshift.apply( this[HOSTS], this[HOSTS].splice( num, this[HOSTS].length ) );
|
||||||
|
return this[HOSTS];
|
||||||
|
}
|
||||||
|
get hosts() {
|
||||||
|
return this[HOSTS].map((host) => new Docker(host));
|
||||||
|
}
|
||||||
|
next() {
|
||||||
|
this.rotate(1);
|
||||||
|
return this.hosts[0];
|
||||||
|
}
|
||||||
|
valueOf() {
|
||||||
|
return this.next();
|
||||||
|
}
|
||||||
|
get host() {
|
||||||
|
return this.next();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = DockerPool;
|
128
lib/SOCKSServer.js
Normal file
128
lib/SOCKSServer.js
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var socks = require('socksv5'),
|
||||||
|
winston = require('winston'),
|
||||||
|
ejs = require('ejs'),
|
||||||
|
domain = require('domain'),
|
||||||
|
shell = require('shelljs'),
|
||||||
|
HOSTS = require('./hosts');
|
||||||
|
|
||||||
|
const SOCKSServer = (function () {
|
||||||
|
const SERVER = Symbol('server');
|
||||||
|
const POOL = Symbol('pool');
|
||||||
|
return class SOCKSServer {
|
||||||
|
constructor(tor_pool) {
|
||||||
|
if (!tor_pool)
|
||||||
|
throw (new Error('no tor pool'));
|
||||||
|
var socks_srv = this;
|
||||||
|
this[SERVER] = socks.createServer(function (info, accept, deny) {
|
||||||
|
if (socks_srv.acl(info)){
|
||||||
|
var d = domain.create();
|
||||||
|
var socket = accept(true);
|
||||||
|
d.on('error', function (err) {
|
||||||
|
winston.warn(err.message);
|
||||||
|
socket && socket.end();
|
||||||
|
});
|
||||||
|
d.add(socket);
|
||||||
|
d.run(function () {
|
||||||
|
socks_srv.connection(info, socket);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
deny();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this[SERVER].useAuth(socks.auth.None());
|
||||||
|
this[POOL] = tor_pool;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve($host) {
|
||||||
|
let result = HOSTS.filter((line) => line.slice(1).some((host) => host === $host))[0];
|
||||||
|
return result || $host;
|
||||||
|
}
|
||||||
|
|
||||||
|
acl(info) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
connection (info, socket) {
|
||||||
|
var socks_srv = this;
|
||||||
|
var incoming_socket = socket,
|
||||||
|
outgoing_socket = null;
|
||||||
|
|
||||||
|
var buffer = Array();
|
||||||
|
|
||||||
|
var onError = function (error) {
|
||||||
|
this.incoming_socket && (typeof(this.incoming_socket.end) === 'function') && this.incoming_socket.end();
|
||||||
|
this.outgoing_socket && (typeof(this.outgoing_socket.end) === 'function') && this.outgoing_socket.end();
|
||||||
|
socks_srv.error(error);
|
||||||
|
};
|
||||||
|
var onClose = function () {
|
||||||
|
if (!buffer)
|
||||||
|
return;
|
||||||
|
buffer = void(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
incoming_socket.on('error', onError.bind({ incoming_socket: incoming_socket, outgoing_socket: outgoing_socket }));
|
||||||
|
incoming_socket.on('data', function (data) {
|
||||||
|
if (outgoing_socket) {
|
||||||
|
outgoing_socket.write(data);
|
||||||
|
} else {
|
||||||
|
buffer[buffer.length] = data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
incoming_socket.on('close', function () {
|
||||||
|
outgoing_socket && outgoing_socket.end();
|
||||||
|
onClose();
|
||||||
|
});
|
||||||
|
|
||||||
|
let srv = socks_srv[POOL].host;
|
||||||
|
|
||||||
|
winston.info(ejs.render("[SOCKS]: <%= info.srcAddr %>:<%= info.srcPort %> => <%= srv.host %>:<%= srv.port %> => <%= info.dstAddr %>:<%= info.dstPort %>", { info: info, srv: srv }));
|
||||||
|
|
||||||
|
info.dstAddr = socks_srv.resolve(info.dstAddr);
|
||||||
|
if (info.distAddr === '0.0.0.0') {
|
||||||
|
incoming_socket.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
socks.connect({
|
||||||
|
host: info.dstAddr,
|
||||||
|
port: info.dstPort,
|
||||||
|
proxyHost: srv.host,
|
||||||
|
proxyPort: srv.port,
|
||||||
|
localDNS: false,
|
||||||
|
auths: [ socks.auth.None() ]
|
||||||
|
}, (function (outgoing) {
|
||||||
|
var incoming_socket = this.incoming_socket;
|
||||||
|
var buffer = this.buffer;
|
||||||
|
outgoing.on('error', onError.bind({ incoming_socket: incoming_socket, outgoing_socket: outgoing }));
|
||||||
|
outgoing.on('close', (function () {
|
||||||
|
this.incoming_socket && (typeof(this.incoming_socket.end) === 'function') && this.incoming_socket.end();
|
||||||
|
onClose();
|
||||||
|
}).bind({ incoming_socket: (incoming_socket || null) }));
|
||||||
|
|
||||||
|
outgoing.on('data', function (data){
|
||||||
|
incoming_socket && incoming_socket.write(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
while (buffer.length > 0) {
|
||||||
|
outgoing.write(buffer.shift());
|
||||||
|
}
|
||||||
|
|
||||||
|
outgoing_socket = outgoing;
|
||||||
|
}).bind({ incoming_socket: incoming_socket, buffer: buffer }));
|
||||||
|
}
|
||||||
|
|
||||||
|
error() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
get server() {
|
||||||
|
return this[SERVER];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = SOCKSServer;
|
126
lib/Tor.js
Normal file
126
lib/Tor.js
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const ejs = require('ejs');
|
||||||
|
const shell = require('shelljs');
|
||||||
|
const _ = require('lodash');
|
||||||
|
const DockerPool = require('./DockerPool');
|
||||||
|
const child = require('child_process');
|
||||||
|
const uuid = require('uuid');
|
||||||
|
const es = require('event-stream');
|
||||||
|
const base32 = require('base32');
|
||||||
|
const winston = require('winston');
|
||||||
|
const temp = require('temp');
|
||||||
|
const async = require('async')
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
temp.track();
|
||||||
|
|
||||||
|
const Tor = (function () {
|
||||||
|
const TOR_IMAGE = 'znetstar/tor';
|
||||||
|
const NAME = Symbol('name');
|
||||||
|
const CONTAINER = Symbol('container');
|
||||||
|
const LOG_MESSAGES = Symbol('log messages');
|
||||||
|
const LOG_MESSAGE = '[Tor Client <%= id %>]: <%= message %>';
|
||||||
|
return class Tor {
|
||||||
|
constructor(options, pool, log, data_dir) {
|
||||||
|
if (!pool) {
|
||||||
|
pool = new DockerPool();
|
||||||
|
}
|
||||||
|
if (!(pool instanceof DockerPool)) {
|
||||||
|
throw new Error('Second argument is not a DockerPool');
|
||||||
|
}
|
||||||
|
this.pool = pool;
|
||||||
|
this.data_dir = data_dir || temp.mkdirSync();
|
||||||
|
this.docker = pool.host;
|
||||||
|
this[LOG_MESSAGES] = !!log;
|
||||||
|
this[NAME] = 'tor-'+(function () {
|
||||||
|
let buf = new Buffer(16);
|
||||||
|
uuid.v4(null, buf, 0);
|
||||||
|
return base32.encode(buf);
|
||||||
|
})();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
get container() {
|
||||||
|
if (this[CONTAINER]) {
|
||||||
|
return this[CONTAINER];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
srv(callback) {
|
||||||
|
var tor = this;
|
||||||
|
async.waterfall([
|
||||||
|
function ($next) {
|
||||||
|
let container = tor[CONTAINER];
|
||||||
|
container.inspect($next);
|
||||||
|
},
|
||||||
|
function (data, $next) {
|
||||||
|
let ip = data.NetworkSettings.IPAddress;
|
||||||
|
if (!ip || ip === '') {
|
||||||
|
return $next(new Error('no ip'));
|
||||||
|
}
|
||||||
|
$next(null, { host: (ip), port: 9050, dns_port: 9053 });
|
||||||
|
}
|
||||||
|
], callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
create(callback) {
|
||||||
|
var tor = this;
|
||||||
|
|
||||||
|
async.waterfall([
|
||||||
|
function ($next) {
|
||||||
|
temp.open('txt',function (err, file) {
|
||||||
|
if (file) {
|
||||||
|
fs.write(file.fd, shell.cat(process.cwd()+'/config/torrc'));
|
||||||
|
fs.close(file.fd)
|
||||||
|
}
|
||||||
|
$next(err, (file && file.path));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function (path, $next) {
|
||||||
|
tor.docker.run(TOR_IMAGE, [], null, { ExposedPorts: { '9050/tcp':{}, '9053/udp':{} } }, { Binds: [ path+':/etc/tor/torrc:ro' ] }, function (error, data, container) {
|
||||||
|
container.remove();
|
||||||
|
}).on('container', (function (container) {
|
||||||
|
var tor = this;
|
||||||
|
|
||||||
|
this[CONTAINER] = container;
|
||||||
|
|
||||||
|
let remove_cont = (function (code) {
|
||||||
|
container.stop(function () {
|
||||||
|
container.remove(function (err) {
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
process.on('SIGINT', remove_cont);
|
||||||
|
process.on('uncaughtException', remove_cont);
|
||||||
|
process.on('exit', remove_cont);
|
||||||
|
|
||||||
|
|
||||||
|
container.attach({ stream: true, stdout: true }, function (err,stream) {
|
||||||
|
stream.pipe(es.map(function (data, cb){
|
||||||
|
if (tor[LOG_MESSAGES])
|
||||||
|
process.stdout.write(ejs.render(LOG_MESSAGE, { id: container.id, message: (data.toString('utf8')) }))
|
||||||
|
cb();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
var srv = null;
|
||||||
|
async.until((function () { return srv; }), function ($next) {
|
||||||
|
tor.srv(function (err, $srv) {
|
||||||
|
srv = $srv;
|
||||||
|
setTimeout($next, 1000);
|
||||||
|
});
|
||||||
|
}, function (err) {
|
||||||
|
callback(null, srv);
|
||||||
|
});
|
||||||
|
}).bind(tor));
|
||||||
|
}
|
||||||
|
], callback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = Tor;
|
62
lib/TorPool.js
Normal file
62
lib/TorPool.js
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const ejs = require('ejs');
|
||||||
|
const shell = require('shelljs');
|
||||||
|
const _ = require('lodash');
|
||||||
|
const Tor = require('./Tor');
|
||||||
|
const async = require('async');
|
||||||
|
|
||||||
|
const TorPool = (function () {
|
||||||
|
const HOSTS = Symbol('hosts');
|
||||||
|
const NUM_SERVERS = Symbol('num');
|
||||||
|
const DOCKER_POOL = Symbol('pool');
|
||||||
|
const TORS = Symbol('tors');
|
||||||
|
return class TorPool {
|
||||||
|
constructor(num, docker_pool) {
|
||||||
|
num = num || 1;
|
||||||
|
this[DOCKER_POOL] = docker_pool;
|
||||||
|
this[NUM_SERVERS] = num;
|
||||||
|
this[HOSTS] = [];
|
||||||
|
this[TORS] = [];
|
||||||
|
}
|
||||||
|
start(callback) {
|
||||||
|
let range = ((size) => Array.from(Array(size).keys()));
|
||||||
|
let srv_array = range(this[NUM_SERVERS]);
|
||||||
|
this[TORS] = [];
|
||||||
|
var pool = this;
|
||||||
|
async.map(srv_array, function (index, next) {
|
||||||
|
let tor = new Tor({}, pool[DOCKER_POOL]);
|
||||||
|
pool[TORS].push(tor);
|
||||||
|
tor.create(function (err) {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
tor.srv(next);
|
||||||
|
});
|
||||||
|
}, function (err, srvs){
|
||||||
|
pool[HOSTS] = srvs;
|
||||||
|
callback(err, pool.hosts);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
rotate(num) {
|
||||||
|
num = num || 1;
|
||||||
|
this[HOSTS].unshift.apply( this[HOSTS], this[HOSTS].splice( num, this[HOSTS].length ) );
|
||||||
|
return this[HOSTS];
|
||||||
|
}
|
||||||
|
get hosts() {
|
||||||
|
return this[HOSTS];
|
||||||
|
}
|
||||||
|
next() {
|
||||||
|
this.rotate(1);
|
||||||
|
return this.hosts[0];
|
||||||
|
}
|
||||||
|
valueOf() {
|
||||||
|
return this.next();
|
||||||
|
}
|
||||||
|
get host() {
|
||||||
|
return this.next();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = TorPool;
|
7
lib/hosts.js
Normal file
7
lib/hosts.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
const shell = require('shelljs');
|
||||||
|
const HOSTS = shell.cat(process.cwd()+'/config/hosts')
|
||||||
|
.split("\n")
|
||||||
|
.filter((host) => (host[0] !== '#') && host.trim().length)
|
||||||
|
.map((line) => line.split(' '));
|
||||||
|
|
||||||
|
module.exports = HOSTS;
|
0
lib/index.js
Normal file
0
lib/index.js
Normal file
20
new_ip.sh
20
new_ip.sh
|
@ -1,20 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Sends a HUP signal to Tor instances, generating a new IP
|
|
||||||
|
|
||||||
source env.sh
|
|
||||||
|
|
||||||
index="0"
|
|
||||||
|
|
||||||
while [ $index -lt $TOR_INSTANCES ]
|
|
||||||
do
|
|
||||||
current_instance="$INSTANCE_PREFIX$index"
|
|
||||||
|
|
||||||
echo "sending signal to $current_instance..."
|
|
||||||
docker exec -t $current_instance /bin/bash -c 'pgrep -f tor | xargs kill -HUP'
|
|
||||||
index=$[$index+1]
|
|
||||||
done
|
|
||||||
|
|
||||||
sleep 1
|
|
||||||
|
|
||||||
exit 0
|
|
22
package.json
22
package.json
|
@ -19,12 +19,20 @@
|
||||||
],
|
],
|
||||||
"homepage": "",
|
"homepage": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"async": "^1.5.0",
|
||||||
|
"base32": "0.0.6",
|
||||||
|
"commander": "^2.9.0",
|
||||||
|
"dockerode": "^2.2.7",
|
||||||
|
"ejs": "^2.3.4",
|
||||||
|
"event-stream": "^3.3.2",
|
||||||
|
"lodash": "^3.10.1",
|
||||||
|
"native-dns": "^0.7.0",
|
||||||
|
"shelljs": "^0.5.3",
|
||||||
|
"socksv5": "0.0.6",
|
||||||
|
"temp": "^0.8.3",
|
||||||
|
"uuid": "^2.0.1",
|
||||||
|
"winston": "^2.1.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {},
|
||||||
"postinstall": "make"
|
"devDependencies": {}
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
7
run.sh
Executable file
7
run.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "using docker host $DOCKER"
|
||||||
|
|
||||||
|
cd /app && node bin/tor-router.js
|
||||||
|
|
||||||
|
exit 0
|
24
shutdown.sh
24
shutdown.sh
|
@ -1,24 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
index="0"
|
|
||||||
|
|
||||||
while [ $index -lt $TOR_INSTANCES ]
|
|
||||||
do
|
|
||||||
current_instance=$INSTANCE_PREFIX$index
|
|
||||||
echo "shutting down $current_instance"
|
|
||||||
docker rm -f $current_instance
|
|
||||||
index=$[index+1]
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "shutting down haproxy..."
|
|
||||||
docker rm -f haproxy
|
|
||||||
|
|
||||||
echo 'removing files...'
|
|
||||||
rm -rf /tmp/haproxy.cfg
|
|
||||||
rm -rf /tmp/tor
|
|
||||||
|
|
||||||
#sleep 5
|
|
||||||
|
|
||||||
echo 'tor router has shut down'
|
|
||||||
|
|
||||||
exit 0
|
|
35
startup.sh
35
startup.sh
|
@ -1,35 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
export TOR_CMD='tor --MaxCircuitDirtiness 60 --RunAsDaemon 0 --CookieAuthentication 0 --controlport 0.0.0.0:9051 --HashedControlPassword 16:4E9480609FC7089F604C83E788481164C25C205288E17D9E5E73EB050B --PidFile tor.pid --SocksPort 0.0.0.0:9050 --DataDirectory /data/tor --ExcludeSingleHopRelays 0 --NewCircuitPeriod 30 --EnforceDistinctSubnets 0 --AllowDotExit 1'
|
|
||||||
|
|
||||||
index=0
|
|
||||||
instances=''
|
|
||||||
#docker -d &
|
|
||||||
|
|
||||||
while [ $index -lt $TOR_INSTANCES ]
|
|
||||||
do
|
|
||||||
current_instance="$INSTANCE_PREFIX$index"
|
|
||||||
echo "removing instance $current_instance..."
|
|
||||||
docker kill $current_instance
|
|
||||||
docker rm -f $current_instance
|
|
||||||
echo "instance $current_instance removed"
|
|
||||||
|
|
||||||
echo "creating instance $current_instance..."
|
|
||||||
docker run -d -v /tmp/tor/$current_instance:/data --name $current_instance --restart="on-failure" znetstar/tor $TOR_CMD
|
|
||||||
echo 'created $current_instance'
|
|
||||||
instances="$instances --link $current_instance:$current_instance"
|
|
||||||
|
|
||||||
index=$[$index+1]
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "removing haproxy..."
|
|
||||||
docker rm -f haproxy
|
|
||||||
|
|
||||||
echo "writing config..."
|
|
||||||
php /opt/haproxy-config.php > /tmp/haproxy.cfg
|
|
||||||
|
|
||||||
echo "started tor-router"
|
|
||||||
clear;
|
|
||||||
docker run --name haproxy -d -p $TOR_PORT:9050 $instances -v /tmp/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro haproxy:1.5.9
|
|
||||||
|
|
||||||
exit 0
|
|
|
@ -1,16 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
wrapdocker &
|
|
||||||
sleep 5
|
|
||||||
|
|
||||||
echo 'starting tor router...'
|
|
||||||
/usr/local/bin/start-tor-router
|
|
||||||
|
|
||||||
docker logs -f haproxy &
|
|
||||||
docker wait haproxy
|
|
||||||
|
|
||||||
echo 'stopping tor router...'
|
|
||||||
/usr/local/bin/stop-tor-router
|
|
||||||
start-stop-daemon --stop --pidfile "/var/run/docker.pid"
|
|
||||||
|
|
||||||
exit 0
|
|
Loading…
Reference in a new issue