mongo-proxy 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/LICENSE.md +9 -0
- data/README.md +151 -0
- data/bin/mongo-proxy +42 -0
- data/lib/mongo-proxy.rb +3 -0
- data/lib/mongo-proxy/auth.rb +151 -0
- data/lib/mongo-proxy/proxy.rb +172 -0
- data/lib/mongo-proxy/wire.rb +526 -0
- data/mongo-proxy.gemspec +36 -0
- data/spec/lib/mongo-proxy/proxy_spec.rb +294 -0
- data/spec/lib/mongo-proxy/wire_spec.rb +317 -0
- data/spec/spec_helper.rb +44 -0
- metadata +232 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 82257f694a4c0d087fd02010aa37c2a160ef2cff
|
4
|
+
data.tar.gz: c7fd83f1ba64daa944a0a55cbe462f5f30c8683f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ac74381e8f4d526f3a24441fb6a21c7a04eedd4473be89edf2f0aedcfb6e0f1accb5a0c5f1218f7ea39fda50b5eb3263067d9478e3d7bd03144e14d40fd08d7a
|
7
|
+
data.tar.gz: 6afb35ffac434d0ab07dc444fc0930cec5a2e80814764ce618e1d59988ae4365688d6d20db1f3e4feb40232f211f5aa6966fbb12463d52ef5c6f7184b8ec0941
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Copyright (C) 2014 Peter Bakkum
|
2
|
+
|
3
|
+
(MIT License)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
+
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
Mongo Proxy
|
2
|
+
===========
|
3
|
+
|
4
|
+
A gem for proxying MongoDB at the wire-protocol level. The proxy intercepts MongoDB communication, presents it in an easy-to-manipulate format, and forwards only desired messages. This approach allows you to filter MongoDB traffic, such as writes, or even inject new messages, such as a message-of-the-day that appears on new connections.
|
5
|
+
|
6
|
+
mongo-proxy includes a command-line interface and an API for running it in a Ruby application. You can write your own hooks to manipulate MongoDB wire traffic as it arrives from the client.
|
7
|
+
|
8
|
+
Installation
|
9
|
+
------------
|
10
|
+
|
11
|
+
`gem install mongo-proxy`
|
12
|
+
|
13
|
+
More information at the [gem page](http://rubygems.org/gems/mongo-proxy).
|
14
|
+
|
15
|
+
Command Line
|
16
|
+
------------
|
17
|
+
|
18
|
+
You can run mongo-proxy from the command line:
|
19
|
+
|
20
|
+
`mongo-proxy [options]`
|
21
|
+
|
22
|
+
Here is an example:
|
23
|
+
|
24
|
+
`mongo-proxy --client-port 29017 --read-only --motd 'Connected to proxy!'`
|
25
|
+
|
26
|
+
This will proxy local client connections to port 29017 to a running MongoDB server at port 27017. Only read queries will be allowed and the client will be told on startup that he is connecting to a proxy server. With the proxy running, a connection looks something like:
|
27
|
+
|
28
|
+
```
|
29
|
+
> mongo --port 29017
|
30
|
+
MongoDB shell version: 2.6.0
|
31
|
+
connecting to: 127.0.0.1:27018/test
|
32
|
+
Server has startup warnings:
|
33
|
+
Connected to proxy!
|
34
|
+
```
|
35
|
+
|
36
|
+
#### Command Line Options
|
37
|
+
|
38
|
+
The following flags can be used when connecting:
|
39
|
+
```
|
40
|
+
--client-host, -h <s>: Set the host to bind the proxy socket on
|
41
|
+
(default: 127.0.0.1)
|
42
|
+
--client-port, -p <i>: Set the port to bind the proxy socket on
|
43
|
+
(default: 27018)
|
44
|
+
--server-host, -H <s>: Set the backend hostname which we proxy
|
45
|
+
(default: 127.0.0.1)
|
46
|
+
--server-port, -P <i>: Set the backend port which we proxy (default:
|
47
|
+
27017)
|
48
|
+
--read-only, -r: Prevent any traffic that writes to the
|
49
|
+
database
|
50
|
+
--motd, -m: Set a message-of-the-day to display to clients
|
51
|
+
when they connect
|
52
|
+
--verbose, --no-verbose, -v: Print out MongoDB wire traffic (default: true)
|
53
|
+
--debug, --no-debug, -d: Print log lines in a more human-readible
|
54
|
+
format (default: true)
|
55
|
+
--version, -e: Print version and exit
|
56
|
+
--help, -l: Show this message
|
57
|
+
|
58
|
+
```
|
59
|
+
|
60
|
+
API
|
61
|
+
---
|
62
|
+
|
63
|
+
You can also use the mongo-proxy functionality directly in Ruby. This approach allows you to add your own hooks to manipulate MongoDB traffic. Here is an example:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
require 'mongo-proxy'
|
67
|
+
|
68
|
+
front = 0
|
69
|
+
back = 0
|
70
|
+
config = {
|
71
|
+
:client_port => 29017,
|
72
|
+
:server_port => 27017,
|
73
|
+
:read_only => true,
|
74
|
+
:debug => true
|
75
|
+
}
|
76
|
+
|
77
|
+
proxy = MongoProxy.new(config)
|
78
|
+
|
79
|
+
m.add_callback_to_front do |conn, msg|
|
80
|
+
front += 1
|
81
|
+
puts "received #{front} client messages so far"
|
82
|
+
msg
|
83
|
+
end
|
84
|
+
|
85
|
+
m.add_callback_to_back do |conn, msg|
|
86
|
+
back += 1
|
87
|
+
puts "forwarded #{back} client messages so far"
|
88
|
+
msg
|
89
|
+
end
|
90
|
+
|
91
|
+
m.start
|
92
|
+
```
|
93
|
+
|
94
|
+
This example opens up a read-only proxy at port 29017. There are two stacks of callbacks: the 'front' callbacks are executed before applying the read-only authorization, while the 'back' callbacks are called after. Thus, the back callbacks will only receive messages that passed authorization. Calling `add_callback_to_front` adds a hook to the front of the front stack, while calling `add_callback_to_back` adds a hook to the back of the back stack. Once you call `start` the proxy will run and show both the messages it receives (because of the debug flag) and the messages from the callback.
|
95
|
+
|
96
|
+
Callbacks are executed and passed the client connection on which a message was received and the message itself as a `Hash`. The callback can make changes to this message, if desired. The callback is expected to return a message to pass along through the stack of callbacks and eventually forwarded to the backend MongoDB server. If a callback returns `nil` then the message will dropped.
|
97
|
+
|
98
|
+
mongo-proxy is a thin layer on top of [em-proxy](https://github.com/igrigorik/em-proxy), and the connection object passed to your hook is the same as the em-proxy connection object. This means that you can call the `send_data` method on it to send a raw message to the client.
|
99
|
+
|
100
|
+
#### MongoProxy Options
|
101
|
+
|
102
|
+
You can use the following options (shown with their default values), when creating a `MongoProxy` object.
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
@config = {
|
106
|
+
:client_host => '127.0.0.1', # Set the host to bind the proxy socket on.
|
107
|
+
:client_port => 29017, # Set the port to bind the proxy socket on.
|
108
|
+
:server_host => '127.0.0.1', # Set the backend host which we proxy.
|
109
|
+
:server_port => 27017, # Set the backend port which we proxy.
|
110
|
+
:motd => nil, # Set a message-of-the-day to display to clients when they connect. nil for none.
|
111
|
+
:read_only => false, # Prevent any traffic that writes to the database.
|
112
|
+
:verbose => false, # Print out MongoDB wire traffic.
|
113
|
+
:logger => nil, # Use this object as the logger instead of creating one.
|
114
|
+
:debug => false # Print log lines in a more human-readible format.
|
115
|
+
}
|
116
|
+
```
|
117
|
+
|
118
|
+
#### Message Format
|
119
|
+
|
120
|
+
Here is an example message passed to a hook:
|
121
|
+
```ruby
|
122
|
+
{
|
123
|
+
:flags => 0,
|
124
|
+
:database => 'test',
|
125
|
+
:collection => 'testcoll',
|
126
|
+
:numberToSkip => 0,
|
127
|
+
:numberToReturn => 4294967295,
|
128
|
+
:query => {
|
129
|
+
"foo" => "bar"
|
130
|
+
},
|
131
|
+
:returnFieldSelector => nil,
|
132
|
+
:header => {
|
133
|
+
:messageLength => 58,
|
134
|
+
:requestID => 1,
|
135
|
+
:responseTo => 0,
|
136
|
+
:opCode => :query
|
137
|
+
}
|
138
|
+
}
|
139
|
+
```
|
140
|
+
|
141
|
+
This format comes from our [wire parsing code](lib/mongo-proxy/wire.rb), and will look similar, but differ slightly, for other operations such as inserts or deletes.
|
142
|
+
|
143
|
+
Testing
|
144
|
+
-------
|
145
|
+
|
146
|
+
Running the unit tests requires a MongoDB instance at port 27018 (nonstandard) and nothing at port 27017. The tests use rspec, so you can run with `bundle exec rspec`.
|
147
|
+
|
148
|
+
License
|
149
|
+
-------
|
150
|
+
|
151
|
+
[The MIT License](LICENSE.md) - Copyright 2014 Peter Bakkum
|
data/bin/mongo-proxy
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'mongo-proxy'
|
4
|
+
require 'trollop'
|
5
|
+
|
6
|
+
opts = Trollop::options do
|
7
|
+
version "mongo-proxy #{MongoProxy::VERSION} (c) Peter Bakkum"
|
8
|
+
banner <<-END
|
9
|
+
mongo-proxy runs a local proxy server for MongoDB. It allows you to watch the MongoDB wire traffic, run hooks on it, and force traffic to be read-only. This command is intended for easy access, you can also access the same functionality with the MongoProxy class.
|
10
|
+
|
11
|
+
Usage:
|
12
|
+
mongo-proxy [options]
|
13
|
+
|
14
|
+
Examples:
|
15
|
+
|
16
|
+
mongo-proxy -P 27017 -p 29017 -r -d
|
17
|
+
(runs a proxy at port 29017 to connect to a local mongo in read-only and debug mode)
|
18
|
+
|
19
|
+
More info can be found at the gem website at github.com/bakks/mongo-proxy
|
20
|
+
|
21
|
+
Command line options:
|
22
|
+
|
23
|
+
END
|
24
|
+
|
25
|
+
opt :client_host, 'Set the host to bind the proxy socket on.', :default => '127.0.0.1', :short => 'h'
|
26
|
+
opt :client_port, 'Set the port to bind the proxy socket on.', :default => 27018, :short => 'p'
|
27
|
+
opt :server_host, 'Set the backend hostname which we proxy.', :default => '127.0.0.1', :short => 'H'
|
28
|
+
opt :server_port, 'Set the backend port which we proxy.', :default => 27017, :short => 'P'
|
29
|
+
opt :read_only, 'Prevent any traffic that writes to the database.', :default => false
|
30
|
+
opt :motd, 'Set a message-of-the-day to display to clients when they connect.', :default => nil
|
31
|
+
opt :verbose, 'Print out MongoDB wire traffic.', :default => true
|
32
|
+
opt :debug, 'Print log lines in a more human-readible format.', :default => true
|
33
|
+
end
|
34
|
+
|
35
|
+
keys = [:client_host, :client_port, :server_host, :server_port, :read_only, :motd, :verbose, :debug]
|
36
|
+
|
37
|
+
args = {}
|
38
|
+
keys.each { |key| args[key] = opts[key] }
|
39
|
+
|
40
|
+
m = MongoProxy.new(args)
|
41
|
+
m.start
|
42
|
+
|
data/lib/mongo-proxy.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
class AuthMongo
|
4
|
+
@@admin_cmd_whitelist = [
|
5
|
+
{ 'ismaster' => 1 },
|
6
|
+
{ 'isMaster' => 1 },
|
7
|
+
{ 'listDatabases' => 1},
|
8
|
+
{
|
9
|
+
'replSetGetStatus' => 1,
|
10
|
+
'forShell' => 1
|
11
|
+
}
|
12
|
+
]
|
13
|
+
|
14
|
+
def initialize(config = nil)
|
15
|
+
@config = config
|
16
|
+
@log = @config[:logger]
|
17
|
+
@request_id = 20
|
18
|
+
@last_error = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def wire_auth(conn, msg)
|
22
|
+
return nil unless msg
|
23
|
+
|
24
|
+
authed, response = auth(conn, msg)
|
25
|
+
|
26
|
+
if !authed
|
27
|
+
@last_error[conn] = true
|
28
|
+
else
|
29
|
+
@last_error[conn] = false
|
30
|
+
end
|
31
|
+
|
32
|
+
if response
|
33
|
+
return WireMongo::build_reply(response, get_request_id, msg[:header][:requestID])
|
34
|
+
else
|
35
|
+
return authed
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def reply_motd
|
42
|
+
motd = @config[:motd]
|
43
|
+
motd = motd.split("\n")
|
44
|
+
return true, {
|
45
|
+
'totalLinesWritten' => motd.size,
|
46
|
+
'log' => motd,
|
47
|
+
'ok' => 1.0
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def reply_unauth(db, coll)
|
52
|
+
@log.info "replying unauthed for collection #{db}.#{coll}"
|
53
|
+
return false, {
|
54
|
+
'ok' => 0,
|
55
|
+
'n' => 0,
|
56
|
+
'code' => 2,
|
57
|
+
'errmsg' => 'Writes and Javascript execution are disallowed in this interface.',
|
58
|
+
'writeErrors' => {
|
59
|
+
'index' => 0,
|
60
|
+
'code' => 2,
|
61
|
+
'errmsg' => 'Writes and Javascript execution are disallowed in this interface.'
|
62
|
+
}
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
def reply_error(err)
|
67
|
+
return false, {
|
68
|
+
'errmsg' => err,
|
69
|
+
'ok' => 0.0
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def reply_ok
|
74
|
+
return true, {
|
75
|
+
'ok' => 1.0
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_request_id
|
80
|
+
x = @request_id
|
81
|
+
@request_id += 1
|
82
|
+
return x
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
def auth(conn, msg)
|
87
|
+
op = msg[:header][:opCode]
|
88
|
+
|
89
|
+
if op == WireMongo::OP_KILL_CURSORS
|
90
|
+
return true, nil
|
91
|
+
end
|
92
|
+
|
93
|
+
db = msg[:database]
|
94
|
+
coll = msg[:collection]
|
95
|
+
query = (msg[:query] or {})
|
96
|
+
|
97
|
+
case op
|
98
|
+
when WireMongo::OP_QUERY, WireMongo::OP_GET_MORE
|
99
|
+
return reply_unauth(db, coll) unless db and coll
|
100
|
+
return reply_unauth(db, coll) if query['$where'] != nil
|
101
|
+
|
102
|
+
# handle authentication process
|
103
|
+
if coll == '$cmd'
|
104
|
+
|
105
|
+
if query['count']
|
106
|
+
# fields key can be nil but must exist
|
107
|
+
unless query.size == 3 and query['query'] and query.has_key? 'fields'
|
108
|
+
return reply_unauth(db, coll)
|
109
|
+
end
|
110
|
+
return true, nil
|
111
|
+
|
112
|
+
elsif query['getlasterror'] == 1
|
113
|
+
if @last_error[conn]
|
114
|
+
return reply_unauth(db, coll)
|
115
|
+
@last_error[conn] = false
|
116
|
+
else
|
117
|
+
return true, nil
|
118
|
+
end
|
119
|
+
|
120
|
+
# allow ismaster query, listDatabases query
|
121
|
+
elsif db == 'admin'
|
122
|
+
if @@admin_cmd_whitelist.include?(query)
|
123
|
+
return true, nil
|
124
|
+
elsif query['getLog'] == 'startupWarnings'
|
125
|
+
if @config[:motd]
|
126
|
+
return reply_motd
|
127
|
+
else
|
128
|
+
return true
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end # if db == 'admin'
|
133
|
+
return reply_unauth(db, coll)
|
134
|
+
end # if coll == '$cmd'
|
135
|
+
|
136
|
+
return true, nil if coll == 'system.namespaces' # list collections
|
137
|
+
return reply_unauth(db, coll) if coll[0] == '$' #other command
|
138
|
+
|
139
|
+
return true, nil
|
140
|
+
|
141
|
+
when WireMongo::OP_UPDATE, WireMongo::OP_INSERT, WireMongo::OP_DELETE
|
142
|
+
#return reply_unauth(db, coll)
|
143
|
+
return false, nil
|
144
|
+
|
145
|
+
else
|
146
|
+
return reply_unauth(db, coll)
|
147
|
+
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'em-proxy'
|
2
|
+
require 'logger'
|
3
|
+
require 'json'
|
4
|
+
require 'pp'
|
5
|
+
require 'socket'
|
6
|
+
require 'timeout'
|
7
|
+
|
8
|
+
|
9
|
+
# This class uses em-proxy to help listen to MongoDB traffic, with some
|
10
|
+
# parsing and filtering capabilities that allow you to enforce a read-only
|
11
|
+
# mode, or use your own arbitrary logic.
|
12
|
+
class MongoProxy
|
13
|
+
VERSION = '1.0.0'
|
14
|
+
|
15
|
+
def initialize(config = nil)
|
16
|
+
# default config values
|
17
|
+
@config = {
|
18
|
+
:client_host => '127.0.0.1', # Set the host to bind the proxy socket on.
|
19
|
+
:client_port => 29017, # Set the port to bind the proxy socket on.
|
20
|
+
:server_host => '127.0.0.1', # Set the backend host which we proxy.
|
21
|
+
:server_port => 27017, # Set the backend port which we proxy.
|
22
|
+
:motd => nil, # Set a message-of-the-day to display to clients when they connect. nil for none.
|
23
|
+
:read_only => false, # Prevent any traffic that writes to the database.
|
24
|
+
:verbose => false, # Print out MongoDB wire traffic.
|
25
|
+
:logger => nil, # Use this object as the logger instead of creating one.
|
26
|
+
:debug => false # Print log lines in a more human-readible format.
|
27
|
+
}
|
28
|
+
@front_callbacks = []
|
29
|
+
@back_callbacks = []
|
30
|
+
|
31
|
+
# apply argument config to the default values
|
32
|
+
(config || []).each do |k, v|
|
33
|
+
if @config.include?(k)
|
34
|
+
@config[k] = v
|
35
|
+
else
|
36
|
+
raise "Unrecognized configuration value: #{k}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# debug implies verbose
|
41
|
+
@config[:verbose] = true if @config[:debug]
|
42
|
+
|
43
|
+
# Set up the logger for mongo proxy. Users can also pass their own
|
44
|
+
# logger in with the :logger config value.
|
45
|
+
unless @config[:logger]
|
46
|
+
@config[:logger] = Logger.new(STDOUT)
|
47
|
+
@config[:logger].level = (@config[:verbose] ? Logger::DEBUG : Logger::WARN)
|
48
|
+
|
49
|
+
if @config[:debug]
|
50
|
+
@config[:logger].formatter = proc do |_, _, _, msg|
|
51
|
+
if msg.is_a?(Hash)
|
52
|
+
"#{JSON::pretty_generate(msg)}\n\n"
|
53
|
+
else
|
54
|
+
"#{msg}\n\n"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
unless port_open?(@config[:server_host], @config[:server_port])
|
61
|
+
raise "Could not connect to MongoDB server at #{@config[:server_host]}.#{@config[:server_port]}"
|
62
|
+
end
|
63
|
+
|
64
|
+
@log = @config[:logger]
|
65
|
+
@auth = AuthMongo.new(@config)
|
66
|
+
end
|
67
|
+
|
68
|
+
def start
|
69
|
+
# em proxy launches a thread, this is the error handler for it
|
70
|
+
EM.error_handler do |e|
|
71
|
+
@log.error [e.inspect, e.backtrace.first]
|
72
|
+
raise e
|
73
|
+
end
|
74
|
+
|
75
|
+
# kick off em-proxy
|
76
|
+
Proxy.start({
|
77
|
+
:host => @config[:client_host],
|
78
|
+
:port => @config[:client_port],
|
79
|
+
:debug => false
|
80
|
+
},
|
81
|
+
&method(:callbacks))
|
82
|
+
end
|
83
|
+
|
84
|
+
def add_callback_to_front(&block)
|
85
|
+
@front_callbacks.insert(0, block)
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_callback_to_back(&block)
|
89
|
+
@back_callbacks << block
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def callbacks(conn)
|
95
|
+
conn.server(:srv, {
|
96
|
+
:host => @config[:server_host],
|
97
|
+
:port => @config[:server_port]})
|
98
|
+
|
99
|
+
conn.on_data do |data|
|
100
|
+
# parse the raw binary message
|
101
|
+
raw_msg, msg = WireMongo.receive(data)
|
102
|
+
|
103
|
+
@log.info 'from client'
|
104
|
+
@log.info msg
|
105
|
+
|
106
|
+
if raw_msg == nil
|
107
|
+
@log.info "Client disconnected"
|
108
|
+
return
|
109
|
+
end
|
110
|
+
|
111
|
+
@front_callbacks.each do |cb|
|
112
|
+
msg = cb.call(conn, msg)
|
113
|
+
break unless msg
|
114
|
+
end
|
115
|
+
next unless msg
|
116
|
+
|
117
|
+
# get auth response about client query
|
118
|
+
authed = (@config[:read_only] == true ? @auth.wire_auth(conn, msg) : true)
|
119
|
+
r = nil
|
120
|
+
|
121
|
+
if authed == true # auth succeeded
|
122
|
+
@back_callbacks.each do |cb|
|
123
|
+
msg = cb.call(conn, msg)
|
124
|
+
break unless msg
|
125
|
+
end
|
126
|
+
next unless msg
|
127
|
+
|
128
|
+
r = WireMongo::write(msg)
|
129
|
+
|
130
|
+
elsif authed.is_a?(Hash) # auth had a direct response
|
131
|
+
response = WireMongo::write(authed)
|
132
|
+
conn.send_data(response)
|
133
|
+
|
134
|
+
else # otherwise drop the message
|
135
|
+
@log.info 'dropping message'
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
r
|
140
|
+
end
|
141
|
+
|
142
|
+
# messages back from the server
|
143
|
+
conn.on_response do |backend, resp|
|
144
|
+
if @config[:verbose]
|
145
|
+
_, msg = WireMongo::receive(resp)
|
146
|
+
@log.info 'from server'
|
147
|
+
@log.info msg
|
148
|
+
end
|
149
|
+
|
150
|
+
resp
|
151
|
+
end
|
152
|
+
|
153
|
+
conn.on_finish do |backend, name|
|
154
|
+
@log.info "closing client connection #{name}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# http://stackoverflow.com/questions/517219/ruby-see-if-a-port-is-open
|
159
|
+
def port_open?(ip, port, seconds=1)
|
160
|
+
Timeout::timeout(seconds) do
|
161
|
+
begin
|
162
|
+
TCPSocket.new(ip, port).close
|
163
|
+
true
|
164
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
165
|
+
false
|
166
|
+
end
|
167
|
+
end
|
168
|
+
rescue Timeout::Error
|
169
|
+
false
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|