web-console 3.6.2 → 4.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.markdown +35 -0
- data/README.markdown +32 -25
- data/lib/web_console.rb +3 -1
- data/lib/web_console/evaluator.rb +5 -3
- data/lib/web_console/exception_mapper.rb +23 -2
- data/lib/web_console/extensions.rb +10 -23
- data/lib/web_console/injector.rb +5 -3
- data/lib/web_console/interceptor.rb +18 -0
- data/lib/web_console/middleware.rb +6 -9
- data/lib/web_console/{whitelist.rb → permissions.rb} +5 -9
- data/lib/web_console/railtie.rb +19 -4
- data/lib/web_console/request.rb +4 -20
- data/lib/web_console/session.rb +11 -9
- data/lib/web_console/source_location.rb +15 -0
- data/lib/web_console/template.rb +2 -3
- data/lib/web_console/templates/console.js.erb +116 -28
- data/lib/web_console/templates/error_page.js.erb +7 -8
- data/lib/web_console/templates/index.html.erb +4 -0
- data/lib/web_console/templates/regular_page.js.erb +24 -0
- data/lib/web_console/templates/style.css.erb +182 -33
- data/lib/web_console/testing/fake_middleware.rb +0 -1
- data/lib/web_console/version.rb +1 -1
- data/lib/web_console/view.rb +5 -0
- data/lib/web_console/whiny_request.rb +4 -4
- metadata +14 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 843f71412a6d2c6a31f35062ad86326656caed6a75de13d9e9c3b09d143ccb3c
|
4
|
+
data.tar.gz: 6a7a70ff565431ff9f1a2f47db2cfaf9498abf95a030e5ea285c27cf42412dab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 34e95ab70102f30b04fb9f538a5773b927773be82e9d350374e50d743bbcc02186d66b71506198cde59e169ad0fbaf291ca15e43aeac1b6bb676bf993de668d5
|
7
|
+
data.tar.gz: 0b3ad53ed8e1d27d06f11bd9d8f07f197e2a60e902fdba4d7cb1c8014eeac7c3cbc5af2f34b359fb6f60fbd005795cfdcc58185144b8e2ca5a8ca18a767182c6
|
data/CHANGELOG.markdown
CHANGED
@@ -2,6 +2,35 @@
|
|
2
2
|
|
3
3
|
## master (unreleased)
|
4
4
|
|
5
|
+
## 4.0.3
|
6
|
+
|
7
|
+
* [#291](https://github.com/rails/web-console/pull/291) Deprecate config.web_console.whitelisted_ips ([@JuanitoFatas])
|
8
|
+
* [#290](https://github.com/rails/web-console/pull/290) Fix Content-Length for rack >= 2.1.0 ([@p8])
|
9
|
+
|
10
|
+
## 4.0.2
|
11
|
+
|
12
|
+
* [#285](https://github.com/rails/web-console/pull/285) Increase timeout on paste ([@celvro])
|
13
|
+
|
14
|
+
## 4.0.1
|
15
|
+
|
16
|
+
* [#279](https://github.com/rails/web-console/pull/279) Fix initial config.web_console.permissions value ([@patorash])
|
17
|
+
|
18
|
+
## 4.0.0
|
19
|
+
|
20
|
+
* [61ce65b5](https://github.com/rails/web-console/commit/61ce65b599f56809de1bd8da6590a80acbd92017) Move to config.web_console.permissions ([@gsamokovarov])
|
21
|
+
* [96127ac1](https://github.com/rails/web-console/commit/96127aac143e1e653fffdc4bb65e1ce0b5ff342d) Introduce Binding#console as an alternative interface ([@gsamokovarov])
|
22
|
+
* [d4591ca5](https://github.com/rails/web-console/commit/d4591ca5396ed15a08818f3da11134852a485b27) Introduce Rails 6 support ([@gsamokovarov])
|
23
|
+
* [f97d8a88](https://github.com/rails/web-console/commit/f97d8a889a38366485e5c5e8985995c19bf61d13) Introduce Ruby 2.6 support ([@gsamokovarov])
|
24
|
+
* [d6deacd9](https://github.com/rails/web-console/commit/d6deacd9d5fcaabf3e3051d6985b53f924f86956) Drop Rails 5 support ([@gsamokovarov])
|
25
|
+
* [90fda878](https://github.com/rails/web-console/commit/90fda8789d402f05647c18f8cdf8e5c3d01692dd) Drop Ruby 2.4 support ([@gsamokovarov])
|
26
|
+
* [#265](https://github.com/rails/web-console/pull/265) Add support for nested exceptions ([@yuki24])
|
27
|
+
|
28
|
+
## 3.7.0
|
29
|
+
|
30
|
+
* [#263](https://github.com/rails/web-console/pull/263) Show binding changes ([@causztic])
|
31
|
+
* [#258](https://github.com/rails/web-console/pull/258) Support Ctrl-A, Ctrl-W and Ctrl-U ([@gsamokovarov])
|
32
|
+
* [#257](https://github.com/rails/web-console/pull/257) Always try to keep the console underneath the website content ([@gsamokovarov])
|
33
|
+
|
5
34
|
## 3.6.2
|
6
35
|
|
7
36
|
* [#255](https://github.com/rails/web-console/pull/255) Fix the truncated HTML body, because of wrong Content-Length header ([@timomeh])
|
@@ -131,3 +160,9 @@ go to 3.1.0 instead.
|
|
131
160
|
[@ybart]: https://github.com/ybart
|
132
161
|
[@fl0l0u]: https://github.com/fl0l0u
|
133
162
|
[@timomeh]: https://github.com/timomeh
|
163
|
+
[@causztic]: https://github.com/causztic
|
164
|
+
[@yuki24]: https://github.com/yuki24
|
165
|
+
[@patorash]: https://github.com/patorash
|
166
|
+
[@celvro]: https://github.com/celvro
|
167
|
+
[@JuanitoFatas]: https://github.com/JuanitoFatas
|
168
|
+
[@p8]: https://github.com/p8
|
data/README.markdown
CHANGED
@@ -16,7 +16,7 @@ _Web Console_ is a debugging tool for your Ruby on Rails applications.
|
|
16
16
|
|
17
17
|
## Installation
|
18
18
|
|
19
|
-
Add the following to your `Gemfile
|
19
|
+
Add the following to your `Gemfile`:
|
20
20
|
|
21
21
|
```ruby
|
22
22
|
group :development do
|
@@ -27,8 +27,8 @@ end
|
|
27
27
|
## Usage
|
28
28
|
|
29
29
|
The web console allows you to create an interactive Ruby session in your
|
30
|
-
browser. Those sessions are launched automatically in case of an error
|
31
|
-
|
30
|
+
browser. Those sessions are launched automatically in case of an error and can
|
31
|
+
also be launched manually in any page.
|
32
32
|
|
33
33
|
For example, calling `console` in a view will display a console in the current
|
34
34
|
page in the context of the view binding.
|
@@ -56,30 +56,30 @@ have multiple ones, `WebConsole::DoubleRenderError` will be raised.
|
|
56
56
|
|
57
57
|
## Configuration
|
58
58
|
|
59
|
-
_Web Console_ allows you to execute arbitrary code on the server,
|
60
|
-
|
59
|
+
_Web Console_ allows you to execute arbitrary code on the server. Therefore, be
|
60
|
+
very careful who you give access to.
|
61
61
|
|
62
|
-
### config.web_console.
|
62
|
+
### config.web_console.permissions
|
63
63
|
|
64
64
|
By default, only requests coming from IPv4 and IPv6 localhosts are allowed.
|
65
65
|
|
66
|
-
`config.web_console.
|
66
|
+
`config.web_console.permissions` lets you control which IP's have access to
|
67
67
|
the console.
|
68
68
|
|
69
|
-
You can
|
70
|
-
console with `192.168.0.100
|
69
|
+
You can allow single IP's or whole networks. Say you want to share your
|
70
|
+
console with `192.168.0.100`:
|
71
71
|
|
72
72
|
```ruby
|
73
73
|
class Application < Rails::Application
|
74
|
-
config.web_console.
|
74
|
+
config.web_console.permissions = '192.168.0.100'
|
75
75
|
end
|
76
76
|
```
|
77
77
|
|
78
|
-
If you want to
|
78
|
+
If you want to allow the whole private network:
|
79
79
|
|
80
80
|
```ruby
|
81
81
|
Rails.application.configure do
|
82
|
-
config.web_console.
|
82
|
+
config.web_console.permissions = '192.168.0.0/16'
|
83
83
|
end
|
84
84
|
```
|
85
85
|
|
@@ -88,13 +88,13 @@ case in 2.0.
|
|
88
88
|
|
89
89
|
### config.web_console.whiny_requests
|
90
90
|
|
91
|
-
When a console cannot be shown for a given IP address or content type,
|
92
|
-
messages
|
91
|
+
When a console cannot be shown for a given IP address or content type,
|
92
|
+
messages such as the following is printed in the server logs:
|
93
93
|
|
94
94
|
> Cannot render console from 192.168.1.133! Allowed networks:
|
95
95
|
> 127.0.0.0/127.255.255.255, ::1
|
96
96
|
|
97
|
-
If you don't
|
97
|
+
If you don't want to see this message anymore, set this option to `false`:
|
98
98
|
|
99
99
|
```ruby
|
100
100
|
Rails.application.configure do
|
@@ -104,7 +104,7 @@ end
|
|
104
104
|
|
105
105
|
### config.web_console.template_paths
|
106
106
|
|
107
|
-
If you
|
107
|
+
If you want to style the console yourself, then you can place `style.css` at a
|
108
108
|
directory pointed by `config.web_console.template_paths`:
|
109
109
|
|
110
110
|
```ruby
|
@@ -113,14 +113,14 @@ Rails.application.configure do
|
|
113
113
|
end
|
114
114
|
```
|
115
115
|
|
116
|
-
You may
|
116
|
+
You may want to check the [templates] folder at the source tree for the files you
|
117
117
|
may override.
|
118
118
|
|
119
119
|
### config.web_console.mount_point
|
120
120
|
|
121
121
|
Usually the middleware of _Web Console_ is mounted at `/__web_console`.
|
122
|
-
If
|
123
|
-
|
122
|
+
If there is a need to change the path, then you can specify it by
|
123
|
+
`config.web_console.mount_point`:
|
124
124
|
|
125
125
|
```ruby
|
126
126
|
Rails.application.configure do
|
@@ -132,26 +132,31 @@ end
|
|
132
132
|
|
133
133
|
### Where did /console go?
|
134
134
|
|
135
|
-
The remote terminal emulator was extracted in its own gem
|
135
|
+
The remote terminal emulator was extracted in its own gem which is no longer
|
136
136
|
bundled with _Web Console_.
|
137
137
|
|
138
138
|
If you miss this feature, check out [rvt].
|
139
139
|
|
140
|
-
### Why I constantly get unavailable session errors?
|
140
|
+
### Why do I constantly get unavailable session errors?
|
141
141
|
|
142
142
|
All of _Web Console_ sessions are stored in memory. If you happen to run on a
|
143
|
-
multi-process server (like Unicorn) you may
|
143
|
+
multi-process server (like Unicorn), you may encounter unavailable session errors
|
144
144
|
while the server is still running. This is because a request may hit a
|
145
145
|
different worker (process) that doesn't have the desired session in memory.
|
146
146
|
To avoid that, if you use such servers in development, configure them so they
|
147
|
-
|
147
|
+
serve requests only out of one process.
|
148
|
+
|
149
|
+
#### Passenger
|
150
|
+
|
151
|
+
Enable sticky sessions for [Passenger on Nginx] or [Passenger on Apache] to
|
152
|
+
prevent unavailable session errors.
|
148
153
|
|
149
154
|
### How to inspect local and instance variables?
|
150
155
|
|
151
156
|
The interactive console executes Ruby code. Invoking `instance_variables` and
|
152
157
|
`local_variables` will give you what you want.
|
153
158
|
|
154
|
-
### Why does console only appear on error pages but not when I call it?
|
159
|
+
### Why does the console only appear on error pages but not when I call it?
|
155
160
|
|
156
161
|
This can be happening if you are using `Rack::Deflater`. Be sure that
|
157
162
|
`WebConsole::Middleware` is used after `Rack::Deflater`. The easiest way to do
|
@@ -163,7 +168,7 @@ Rails.application.configure do
|
|
163
168
|
end
|
164
169
|
```
|
165
170
|
|
166
|
-
### Why I
|
171
|
+
### Why am I getting an undefined method `web_console`?
|
167
172
|
|
168
173
|
Make sure your configuration lives in `config/environments/development.rb`.
|
169
174
|
|
@@ -183,3 +188,5 @@ Make sure your configuration lives in `config/environments/development.rb`.
|
|
183
188
|
[templates]: https://github.com/rails/web-console/tree/master/lib/web_console/templates
|
184
189
|
[rvt]: https://github.com/gsamokovarov/rvt
|
185
190
|
[contributors]: https://github.com/rails/web-console/graphs/contributors
|
191
|
+
[Passenger on Nginx]: https://www.phusionpassenger.com/library/config/nginx/reference/#passengerstickysessions
|
192
|
+
[Passenger on Apache]: https://www.phusionpassenger.com/library/config/apache/reference/#passengerstickysessions
|
data/lib/web_console.rb
CHANGED
@@ -11,12 +11,14 @@ module WebConsole
|
|
11
11
|
autoload :ExceptionMapper
|
12
12
|
autoload :Session
|
13
13
|
autoload :Injector
|
14
|
+
autoload :Interceptor
|
14
15
|
autoload :Request
|
15
16
|
autoload :WhinyRequest
|
16
|
-
autoload :
|
17
|
+
autoload :Permissions
|
17
18
|
autoload :Template
|
18
19
|
autoload :Middleware
|
19
20
|
autoload :Context
|
21
|
+
autoload :SourceLocation
|
20
22
|
|
21
23
|
autoload_at "web_console/errors" do
|
22
24
|
autoload :Error
|
@@ -8,9 +8,11 @@ module WebConsole
|
|
8
8
|
# return a string and will format exception output.
|
9
9
|
class Evaluator
|
10
10
|
# Cleanses exceptions raised inside #eval.
|
11
|
-
cattr_reader :cleaner
|
12
|
-
|
13
|
-
|
11
|
+
cattr_reader :cleaner, default: begin
|
12
|
+
cleaner = ActiveSupport::BacktraceCleaner.new
|
13
|
+
cleaner.add_silencer { |line| line.start_with?(File.expand_path("..", __FILE__)) }
|
14
|
+
cleaner
|
15
|
+
end
|
14
16
|
|
15
17
|
def initialize(binding = TOPLEVEL_BINDING)
|
16
18
|
@binding = binding
|
@@ -2,9 +2,28 @@
|
|
2
2
|
|
3
3
|
module WebConsole
|
4
4
|
class ExceptionMapper
|
5
|
+
attr_reader :exc
|
6
|
+
|
7
|
+
def self.follow(exc)
|
8
|
+
mappers = [new(exc)]
|
9
|
+
|
10
|
+
while cause = (cause || exc).cause
|
11
|
+
mappers << new(cause)
|
12
|
+
end
|
13
|
+
|
14
|
+
mappers
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.find_binding(mappers, exception_object_id)
|
18
|
+
mappers.detect do |exception_mapper|
|
19
|
+
exception_mapper.exc.object_id == exception_object_id.to_i
|
20
|
+
end || mappers.first
|
21
|
+
end
|
22
|
+
|
5
23
|
def initialize(exception)
|
6
24
|
@backtrace = exception.backtrace
|
7
25
|
@bindings = exception.bindings
|
26
|
+
@exc = exception
|
8
27
|
end
|
9
28
|
|
10
29
|
def first
|
@@ -22,13 +41,15 @@ module WebConsole
|
|
22
41
|
line = line.to_i
|
23
42
|
|
24
43
|
@bindings.find do |binding|
|
25
|
-
|
44
|
+
source_location = SourceLocation.new(binding)
|
45
|
+
source_location.path == file && source_location.lineno == line
|
26
46
|
end
|
27
47
|
end
|
28
48
|
|
29
49
|
def guess_the_first_application_binding
|
30
50
|
@bindings.find do |binding|
|
31
|
-
|
51
|
+
source_location = SourceLocation.new(binding)
|
52
|
+
source_location.path.to_s.start_with?(Rails.root.to_s)
|
32
53
|
end
|
33
54
|
end
|
34
55
|
end
|
@@ -8,8 +8,8 @@ module Kernel
|
|
8
8
|
# If +binding+ isn't explicitly given it will default to the binding of the
|
9
9
|
# previous frame. E.g. the one that invoked +console+.
|
10
10
|
#
|
11
|
-
# Raises DoubleRenderError if a
|
12
|
-
# detected.
|
11
|
+
# Raises +DoubleRenderError+ if a more than one +console+ invocation per
|
12
|
+
# request is detected.
|
13
13
|
def console(binding = Bindex.current_bindings.second)
|
14
14
|
raise WebConsole::DoubleRenderError if Thread.current[:__web_console_binding]
|
15
15
|
|
@@ -22,26 +22,13 @@ module Kernel
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
Thread.current[:__web_console_exception] = error
|
34
|
-
|
35
|
-
# ActionView::Template::Error bypass ExceptionWrapper original
|
36
|
-
# exception following. The backtrace in the view is generated from
|
37
|
-
# reaching out to original_exception in the view.
|
38
|
-
if error.is_a?(ActionView::Template::Error)
|
39
|
-
Thread.current[:__web_console_exception] = error.cause
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
alias_method :render_exception_without_web_console, :render_exception
|
45
|
-
alias_method :render_exception, :render_exception_with_web_console
|
25
|
+
class Binding
|
26
|
+
# Instructs Web Console to render a console in the current binding, without
|
27
|
+
# the need to unroll the stack.
|
28
|
+
#
|
29
|
+
# Raises +DoubleRenderError+ if a more than one +console+ invocation per
|
30
|
+
# request is detected.
|
31
|
+
def console
|
32
|
+
Kernel.console(self)
|
46
33
|
end
|
47
34
|
end
|
data/lib/web_console/injector.rb
CHANGED
@@ -13,9 +13,11 @@ module WebConsole
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def inject(content)
|
16
|
-
#
|
17
|
-
# the
|
18
|
-
@headers
|
16
|
+
# Set Content-Length header to the size of the current body
|
17
|
+
# + the extra content. Otherwise the response will be truncated.
|
18
|
+
if @headers["Content-Length"]
|
19
|
+
@headers["Content-Length"] = @body.bytesize + content.bytesize
|
20
|
+
end
|
19
21
|
|
20
22
|
[
|
21
23
|
if position = @body.rindex("</body>")
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module WebConsole
|
2
|
+
module Interceptor
|
3
|
+
def self.call(request, exception)
|
4
|
+
backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner")
|
5
|
+
error = ActionDispatch::ExceptionWrapper.new(backtrace_cleaner, exception).exception
|
6
|
+
|
7
|
+
# Get the original exception if ExceptionWrapper decides to follow it.
|
8
|
+
Thread.current[:__web_console_exception] = error
|
9
|
+
|
10
|
+
# ActionView::Template::Error bypass ExceptionWrapper original
|
11
|
+
# exception following. The backtrace in the view is generated from
|
12
|
+
# reaching out to original_exception in the view.
|
13
|
+
if error.is_a?(ActionView::Template::Error)
|
14
|
+
Thread.current[:__web_console_exception] = error.cause
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -6,11 +6,8 @@ module WebConsole
|
|
6
6
|
class Middleware
|
7
7
|
TEMPLATES_PATH = File.expand_path("../templates", __FILE__)
|
8
8
|
|
9
|
-
cattr_accessor :mount_point
|
10
|
-
|
11
|
-
|
12
|
-
cattr_accessor :whiny_requests
|
13
|
-
@@whiny_requests = true
|
9
|
+
cattr_accessor :mount_point, default: "/__web_console"
|
10
|
+
cattr_accessor :whiny_requests, default: true
|
14
11
|
|
15
12
|
def initialize(app)
|
16
13
|
@app = app
|
@@ -19,7 +16,7 @@ module WebConsole
|
|
19
16
|
def call(env)
|
20
17
|
app_exception = catch :app_exception do
|
21
18
|
request = create_regular_or_whiny_request(env)
|
22
|
-
return call_app(env) unless request.
|
19
|
+
return call_app(env) unless request.permitted?
|
23
20
|
|
24
21
|
if id = id_for_repl_session_update(request)
|
25
22
|
return update_repl_session(id, request)
|
@@ -27,6 +24,7 @@ module WebConsole
|
|
27
24
|
return change_stack_trace(id, request)
|
28
25
|
end
|
29
26
|
|
27
|
+
|
30
28
|
status, headers, body = call_app(env)
|
31
29
|
|
32
30
|
if (session = Session.from(Thread.current)) && acceptable_content_type?(headers)
|
@@ -54,7 +52,7 @@ module WebConsole
|
|
54
52
|
private
|
55
53
|
|
56
54
|
def acceptable_content_type?(headers)
|
57
|
-
|
55
|
+
headers["Content-Type"].to_s.include?("html")
|
58
56
|
end
|
59
57
|
|
60
58
|
def json_response(opts = {})
|
@@ -66,7 +64,6 @@ module WebConsole
|
|
66
64
|
end
|
67
65
|
|
68
66
|
def json_response_with_session(id, request, opts = {})
|
69
|
-
return respond_with_unacceptable_request unless request.acceptable?
|
70
67
|
return respond_with_unavailable_session(id) unless session = Session.find(id)
|
71
68
|
|
72
69
|
json_response(opts) { yield session }
|
@@ -113,7 +110,7 @@ module WebConsole
|
|
113
110
|
|
114
111
|
def change_stack_trace(id, request)
|
115
112
|
json_response_with_session(id, request) do |session|
|
116
|
-
session.switch_binding_to(request.params[:frame_id])
|
113
|
+
session.switch_binding_to(request.params[:frame_id], request.params[:exception_object_id])
|
117
114
|
|
118
115
|
{ ok: true }
|
119
116
|
end
|
@@ -3,20 +3,16 @@
|
|
3
3
|
require "ipaddr"
|
4
4
|
|
5
5
|
module WebConsole
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
# networks.
|
10
|
-
class Whitelist
|
11
|
-
# IPv4 and IPv6 localhost should be always whitelisted.
|
12
|
-
ALWAYS_WHITELISTED_NETWORKS = %w( 127.0.0.0/8 ::1 )
|
6
|
+
class Permissions
|
7
|
+
# IPv4 and IPv6 localhost should be always allowed.
|
8
|
+
ALWAYS_PERMITTED_NETWORKS = %w( 127.0.0.0/8 ::1 )
|
13
9
|
|
14
10
|
def initialize(networks = nil)
|
15
11
|
@networks = normalize_networks(networks).map(&method(:coerce_network_to_ipaddr)).uniq
|
16
12
|
end
|
17
13
|
|
18
14
|
def include?(network)
|
19
|
-
@networks.any? { |
|
15
|
+
@networks.any? { |permission| permission.include?(network.to_s) }
|
20
16
|
rescue IPAddr::InvalidAddressError
|
21
17
|
false
|
22
18
|
end
|
@@ -28,7 +24,7 @@ module WebConsole
|
|
28
24
|
private
|
29
25
|
|
30
26
|
def normalize_networks(networks)
|
31
|
-
Array(networks).concat(
|
27
|
+
Array(networks).concat(ALWAYS_PERMITTED_NETWORKS)
|
32
28
|
end
|
33
29
|
|
34
30
|
def coerce_network_to_ipaddr(network)
|