-
Notifications
You must be signed in to change notification settings - Fork 1
/
per_ip_server.lua
133 lines (115 loc) · 3.64 KB
/
per_ip_server.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env lua
-- -*-lua-*-
--
-- $Id: per_ip_server.lua $
--
-- Author: Markus Stenberg <markus [email protected]>
--
-- Copyright (c) 2013 cisco Systems, Inc.
--
-- Created: Thu May 16 14:06:16 2013 mstenber
-- Last modified: Wed Jul 24 23:18:35 2013 mstenber
-- Edit time: 30 min
--
-- This is a server instance controller, which maintains per-ip
-- instance of a server, and keeps each of those instances completely
-- separate from each other.
-- The reason for this is simple: Given standard POSIX-ish basic API
-- we get from luasocket, we can't determine target address we receive
-- datagrams at, and we cannot ensure our source address matches that
-- when sending reply. So (for example) our DNS traffic looks like
-- bogons.
-- So what we do, is start one dns server per IP address, and deduce
-- the target from that - we can then use simple sendto/receivefrom on
-- those sockets to get correct-looking source addresses.
-- (In a home network, this should not be necessary (hopefully no
-- strict filters), but it might be, if resolver is paranoid - and we
-- don't lose anything by doing this, so we do it.)
require 'mst'
module(..., package.seeall)
per_ip_server = mst.create_class{class='per_ip_server',
mandatory={'create_callback'}}
function per_ip_server:init()
self.servers = {}
end
function per_ip_server:repr_data()
return mst.repr{servers=self.servers and mst.table_count(self.servers) or nil}
end
function per_ip_server:uninit()
for ip, o in pairs(self.servers)
do
o:done()
end
self:detach_skv()
end
function per_ip_server:set_ips(l)
self:d('set_ips', l)
-- convert to a set
local s = mst.array_to_table(l)
local fails
mst.sync_tables(self.servers, s,
-- remove
function (k, o)
o:done()
self.servers[k] = nil
end,
-- add
function (k, o)
local s = self.create_callback(k)
if s
then
self.servers[k] = s
else
fails = fails or 0
fails = fails + 1
end
end
)
if fails
then
self:d('failures', fails, 'retrying in a second')
local t = ssloop.loop():new_timeout_delta(1, function ()
self:d('retry callback')
self:set_ips(l)
end)
t:start()
end
end
function per_ip_server:detach_skv()
if not self.skv
then
return
end
self.skv:remove_change_observer(self.f, elsa_pa.OSPF_LAP_KEY)
self.skv = nil
self.f = nil
end
function per_ip_server:attach_skv(skv, f)
-- detach if we already were attached
self:detach_skv()
-- and attach now
self.skv = skv
self.f = function (_, pl)
-- we can ignore key, we know it pl = list with
-- relevant bit the 'address' (while it's just one IP in
-- practise)
-- convert to normal IP's
local l = {}
for i, lap in ipairs(pl)
do
local a = lap.address
if a
then
if not f or f(lap)
then
-- is this even neccessary? probably, given where we get
-- these addresses from..
a = mst.string_split(a, '/')[1]
table.insert(l, a)
end
end
end
self:set_ips(l)
end
self.skv:add_change_observer(self.f, elsa_pa.OSPF_LAP_KEY)
end