pomelo-router 0.0.2
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 +15 -0
- data/bin/pomelo +6 -0
- data/config.toml.example +85 -0
- data/lib/pomelo.rb +9 -0
- data/lib/pomelo/opts.rb +39 -0
- data/lib/pomelo/parser.rb +158 -0
- metadata +63 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ODc0MzUwYWIxZWJhMWUwYzVmY2ZjNzkyNjk4ZWFlZGNiOTkzMmQwMg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZTAyMDU2ZmEyODkxMWQ5MjFkMWM1MmQxNGVjMzdjOGQyNGIyZjkyOQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YjY3MGQ2Njg3NGJiZjgyYTZlYWFiMGY4NGYxYjQxYTA5ZDU1ZjQwODk4YmI3
|
10
|
+
ZDNkYWI0NjI5NzI1ODZmNzhhZjA5NDY4ZjBlZjAzMjE4YTQ1ZjYyYWMzNTI0
|
11
|
+
NTM3Y2ZlYzU2Y2NkZmIyYTczMTk0NWI4N2QyODZiZTk2Njc1MGU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MTNmZjdkMDg4OWE1MzBhNDJhOTZhMGE1MjU4MTYzOTBhZjFmNjg5MDFiZmQ3
|
14
|
+
OGEwODNkMTA0YzBkMmNkNTljMjg3NzY2NGE0NjI5YjAxOGU1MWEyYTZiNDU3
|
15
|
+
YjkyNzQzYzJlMmM5ZWVlMTc1NTliMDQ5MWRhNDk3MTIxYTAxOTk=
|
data/bin/pomelo
ADDED
data/config.toml.example
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
[networks]
|
2
|
+
# required, the loopback device, normally will be lo or lo0
|
3
|
+
loopback = "lo"
|
4
|
+
allow_icmp = true
|
5
|
+
|
6
|
+
[networks.internet]
|
7
|
+
ip = "111.111.111.111"
|
8
|
+
dev = "eth0"
|
9
|
+
|
10
|
+
[networks.locals]
|
11
|
+
|
12
|
+
[networks.locals.office]
|
13
|
+
net = "192.168.0.0/24"
|
14
|
+
dev = "eth1"
|
15
|
+
[networks.locals.guest]
|
16
|
+
net = "192.168.1.0/24"
|
17
|
+
dev = "eth1"
|
18
|
+
|
19
|
+
[networks.externals]
|
20
|
+
[networks.externals.vpn]
|
21
|
+
host = "192.168.99.2/24"
|
22
|
+
dev = "tun0"
|
23
|
+
|
24
|
+
# custom host/ip ranges definitions
|
25
|
+
[groups]
|
26
|
+
[groups.router]
|
27
|
+
host = "192.168.0.1"
|
28
|
+
[groups.www]
|
29
|
+
host = "192.168.0.2"
|
30
|
+
[groups.users]
|
31
|
+
range = "192.168.0.100-192.168.0.199"
|
32
|
+
|
33
|
+
|
34
|
+
[traffic]
|
35
|
+
# default iptables rule, allow or deny
|
36
|
+
# if you set this to be deny, you will
|
37
|
+
# have to manually set the ports
|
38
|
+
# in the ports section
|
39
|
+
global = "deny"
|
40
|
+
|
41
|
+
|
42
|
+
# openning ports on router
|
43
|
+
# not necessary when traffic.global is "allow"
|
44
|
+
[[ports]]
|
45
|
+
protocol = "tcp"
|
46
|
+
port = 22
|
47
|
+
dev = "eth0"
|
48
|
+
[[ports]]
|
49
|
+
protocol = "tcp"
|
50
|
+
port = 8080
|
51
|
+
dev = "eth0"
|
52
|
+
[[ports]]
|
53
|
+
protocol = "tcp"
|
54
|
+
port = 443
|
55
|
+
dev = "eth0"
|
56
|
+
|
57
|
+
|
58
|
+
# rules
|
59
|
+
[[rules]]
|
60
|
+
# access vpns for users
|
61
|
+
method = "gateway"
|
62
|
+
from = "#{groups.users}"
|
63
|
+
to = "#{networks.externals.vpn}"
|
64
|
+
|
65
|
+
# gateway settings
|
66
|
+
[[rules]]
|
67
|
+
method = "gateway"
|
68
|
+
from = "#{networks.locals.office}"
|
69
|
+
to = "#{networks.internet}"
|
70
|
+
[[rules]]
|
71
|
+
method = "gateway"
|
72
|
+
from = "#{networks.locals.guest}"
|
73
|
+
to = "#{networks.internet}"
|
74
|
+
|
75
|
+
# port forwarding
|
76
|
+
[[rules]]
|
77
|
+
method = "forward"
|
78
|
+
from = 8080
|
79
|
+
protocol = "tcp"
|
80
|
+
to = "#{groups.www.host}:80"
|
81
|
+
[[rules]]
|
82
|
+
method = "forward"
|
83
|
+
from = "50000:60000"
|
84
|
+
protocol = "tcp"
|
85
|
+
to = "#{groups.www.host}"
|
data/lib/pomelo.rb
ADDED
data/lib/pomelo/opts.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'optparse/time'
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
module Pomelo
|
6
|
+
class Opts
|
7
|
+
def self.parse(args)
|
8
|
+
options = OpenStruct.new
|
9
|
+
options.mode = "run"
|
10
|
+
options.config_file = nil
|
11
|
+
|
12
|
+
opt = OptionParser.new do |opts|
|
13
|
+
opts.banner = "Usage: pomelo [-rp] path/to/config.yaml"
|
14
|
+
opts.separator ""
|
15
|
+
opts.separator "Specific options:"
|
16
|
+
|
17
|
+
opts.on("-r", "--run", "run commands") do
|
18
|
+
options.mode = "run"
|
19
|
+
end
|
20
|
+
opts.on("-p", "--print", "print commands") do
|
21
|
+
options.mode = "print"
|
22
|
+
end
|
23
|
+
opts.on("-c", "--configi [PATH]", String, "config file path") do |f|
|
24
|
+
options.config_file = f
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.separator ""
|
28
|
+
opts.separator "Common options:"
|
29
|
+
opts.on_tail("-h", "--help", "Show help message") do
|
30
|
+
puts opts
|
31
|
+
exit
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
opt.parse!(args)
|
36
|
+
return options
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'toml'
|
2
|
+
|
3
|
+
module Pomelo
|
4
|
+
class Parser
|
5
|
+
def initialize(opts)
|
6
|
+
@opts = opts
|
7
|
+
@commands = []
|
8
|
+
|
9
|
+
@config = get_config
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse
|
13
|
+
parse_routes
|
14
|
+
parse_iptables
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
parse
|
19
|
+
run_commands = @commands.join("\n")
|
20
|
+
if print_only?
|
21
|
+
puts run_commands
|
22
|
+
else
|
23
|
+
system run_commands
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def print_only?
|
30
|
+
return @opts.mode == "print"
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_config
|
34
|
+
config_file = @opts.config_file
|
35
|
+
unless config_file
|
36
|
+
puts "config file required"
|
37
|
+
exit
|
38
|
+
end
|
39
|
+
|
40
|
+
begin
|
41
|
+
config = TOML.load_file(config_file)
|
42
|
+
rescue Exception => e
|
43
|
+
puts e
|
44
|
+
puts e.backtrace.join("\n")
|
45
|
+
exit
|
46
|
+
end
|
47
|
+
|
48
|
+
return config
|
49
|
+
end
|
50
|
+
|
51
|
+
def parse_routes
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse_iptables
|
55
|
+
init_iptables
|
56
|
+
open_ports
|
57
|
+
traffic_rules
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_command(cmd)
|
61
|
+
@commands << cmd
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_value(key)
|
65
|
+
parts = key.split "."
|
66
|
+
c = @config
|
67
|
+
parts.each do |p|
|
68
|
+
c = c[p]
|
69
|
+
end
|
70
|
+
|
71
|
+
# parsing quotes
|
72
|
+
c = parse_value(c) if c.is_a?(String)
|
73
|
+
|
74
|
+
return c
|
75
|
+
end
|
76
|
+
|
77
|
+
def parse_value(str)
|
78
|
+
return str.gsub(/\#\{([^\}]+)\}/) do |s|
|
79
|
+
a = s.gsub(/[\#\{\}]/, "")
|
80
|
+
return get_value(a)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def init_iptables
|
85
|
+
s = get_value("traffic.global") == "allow" ? "ACCEPT" : "DROP"
|
86
|
+
lo = get_value("networks.loopback")
|
87
|
+
add_command "iptables -F"
|
88
|
+
add_command "iptables -P INPUT #{s}"
|
89
|
+
add_command "iptables -P OUTPUT #{s}"
|
90
|
+
add_command "iptables -P FORWARD #{s}"
|
91
|
+
# allow loopback
|
92
|
+
add_command "iptables -A INPUT -i #{lo} -j ACCEPT"
|
93
|
+
add_command "iptables -A OUTPUT -o #{lo} -j ACCEPT"
|
94
|
+
# allow ping
|
95
|
+
if get_value("networks.allow_icmp")
|
96
|
+
add_command "iptables -A INPUT -p icmp -j ACCEPT"
|
97
|
+
add_command "iptables -A OUTPUT -p icmp -j ACCEPT"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def open_ports
|
102
|
+
get_value("ports").each do |p|
|
103
|
+
add_command "iptables -A INPUT -i #{p["dev"]} -p #{p["protocol"]} --dport #{p["port"]} -j ACCEPT"
|
104
|
+
add_command "iptables -A OUTPUT -o #{p["dev"]} -p #{p["protocol"]} --sport #{p["port"]} -j ACCEPT"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def traffic_rules
|
109
|
+
get_value("rules").each do |r|
|
110
|
+
parse_rule(r)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def parse_rule(r)
|
115
|
+
method = r["method"]
|
116
|
+
if method == "gateway"
|
117
|
+
parse_gateway_rule(r)
|
118
|
+
elsif method == "forward"
|
119
|
+
parse_forward_rule(r)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def parse_gateway_rule(r)
|
124
|
+
from = parse_value(r["from"])
|
125
|
+
to = parse_value(r["to"])
|
126
|
+
source = nil
|
127
|
+
|
128
|
+
if from["host"]
|
129
|
+
source = "-s #{from["host"]}"
|
130
|
+
elsif from["net"]
|
131
|
+
source = "-s #{from["net"]}"
|
132
|
+
elsif from["range"]
|
133
|
+
source = "-m iprange --src-range #{from["range"]}"
|
134
|
+
else
|
135
|
+
raise "from must contain host or range"
|
136
|
+
end
|
137
|
+
|
138
|
+
add_command "iptables -t nat -A POSTROUTING #{source} -o #{to["dev"]} -j MASQUERADE"
|
139
|
+
end
|
140
|
+
|
141
|
+
def parse_forward_rule(r)
|
142
|
+
from = r["from"]
|
143
|
+
protocol = r["protocol"] || "tcp"
|
144
|
+
# forward requires host for destination
|
145
|
+
to_host, to_port = parse_value(r["to"]).split(":")
|
146
|
+
if to_port
|
147
|
+
to = "#{to_host}:#{to_port}"
|
148
|
+
else
|
149
|
+
to_port = from
|
150
|
+
to = to_host
|
151
|
+
end
|
152
|
+
|
153
|
+
add_command "iptables -t nat -A PREROUTING -p #{protocol} --dport #{from} -j DNAT --to #{to}"
|
154
|
+
add_command "iptables -A FORWARD -p #{protocol} -d #{to_host} --dport #{to_port} -j ACCEPT"
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pomelo-router
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Leon Chen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-09-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: toml
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.1.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.1.2
|
27
|
+
description: linux router network setup automation
|
28
|
+
email: leonhart.chen@gmail.com
|
29
|
+
executables:
|
30
|
+
- pomelo
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- bin/pomelo
|
35
|
+
- config.toml.example
|
36
|
+
- lib/pomelo.rb
|
37
|
+
- lib/pomelo/opts.rb
|
38
|
+
- lib/pomelo/parser.rb
|
39
|
+
homepage: https://github.com/leonchen/pomelo
|
40
|
+
licenses:
|
41
|
+
- MIT
|
42
|
+
metadata: {}
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
requirements: []
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 2.4.6
|
60
|
+
signing_key:
|
61
|
+
specification_version: 4
|
62
|
+
summary: pomelo-router
|
63
|
+
test_files: []
|