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.
@@ -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=
@@ -0,0 +1,6 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'pomelo'
4
+
5
+ p = Pomelo.from_argv(ARGV)
6
+ p.run
@@ -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}"
@@ -0,0 +1,9 @@
1
+ require 'pomelo/opts'
2
+ require 'pomelo/parser'
3
+
4
+ module Pomelo
5
+ def Pomelo.from_argv(argv)
6
+ opts = Opts.parse(argv)
7
+ return Parser.new(opts)
8
+ end
9
+ end
@@ -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: []