diff options
-rw-r--r-- | db/migrate/20130204065900_split_perimeter_parameters.rb | 30 | ||||
-rw-r--r-- | misc/freeswitch/scripts/common/perimeter.lua | 23 | ||||
-rw-r--r-- | misc/freeswitch/scripts/event/perimeter_defense.lua | 51 |
3 files changed, 89 insertions, 15 deletions
diff --git a/db/migrate/20130204065900_split_perimeter_parameters.rb b/db/migrate/20130204065900_split_perimeter_parameters.rb new file mode 100644 index 0000000..b29bb29 --- /dev/null +++ b/db/migrate/20130204065900_split_perimeter_parameters.rb @@ -0,0 +1,30 @@ +class SplitPerimeterParameters < ActiveRecord::Migration + def up + GsParameter.where(:entity => 'perimeter', :section => 'checks').destroy_all + GsParameter.where(:entity => 'perimeter', :section => 'bad_headers').destroy_all + GsParameter.create(:entity => 'perimeter', :section => 'general', :name => 'ban_command', :value => 'sudo /sbin/service shorewall refresh', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks_register', :name => 'check_frequency', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks_register', :name => 'check_username_scan', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks_register', :name => 'check_bad_headers', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks_call', :name => 'check_frequency', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks_call', :name => 'check_bad_headers', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers_register', :name => 'user_agent', :value => '^friendly.scanner$', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers_register', :name => 'to_user', :value => '^%d+', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers_register', :name => 'auth_result', :value => '^FORBIDDEN$', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers_call', :name => 'user_agent', :value => '^friendly.scanner$', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers_call', :name => 'hangup_cause', :value => '^MANDATORY_IE_MISSING', :class_type => 'String', :description => '') + end + + def down + GsParameter.where(:entity => 'perimeter', :section => 'checks_register').destroy_all + GsParameter.where(:entity => 'perimeter', :section => 'checks_call').destroy_all + GsParameter.where(:entity => 'perimeter', :section => 'bad_headers_register').destroy_all + GsParameter.where(:entity => 'perimeter', :section => 'bad_headers_call').destroy_all + GsParameter.create(:entity => 'perimeter', :section => 'checks', :name => 'check_frequency', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks', :name => 'check_username_scan', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks', :name => 'check_bad_headers', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers', :name => 'user_agent', :value => '^friendly.scanner$', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers', :name => 'to_user', :value => '^%d+', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers', :name => 'auth_result', :value => '^FORBIDDEN$', :class_type => 'String', :description => '') + end +end diff --git a/misc/freeswitch/scripts/common/perimeter.lua b/misc/freeswitch/scripts/common/perimeter.lua index 5de86bf..0670fee 100644 --- a/misc/freeswitch/scripts/common/perimeter.lua +++ b/misc/freeswitch/scripts/common/perimeter.lua @@ -42,6 +42,8 @@ function Perimeter.setup(self, event) self.ban_command = 'sudo /sbin/service shorewall refresh'; self.ban_threshold = 20; self.ban_tries = 1; + self.checks = { register = {}, call = {} }; + self.bad_headers = { register = {}, call = {} }; if config and config.general then for key, value in pairs(config.general) do @@ -49,8 +51,10 @@ function Perimeter.setup(self, event) end end - self.checks = config.checks; - self.bad_headers = config.bad_headers; + self.checks.register = config.checks_register or {}; + self.checks.call = config.checks_call or {}; + self.bad_headers.register = config.bad_headers_register; + self.bad_headers.call = config.bad_headers_call; self.log:info('[perimeter] PERIMETER - setup perimeter defense'); end @@ -66,7 +70,7 @@ function Perimeter.record_load(self, event) span_start = event.timestamp, points = 0, banned = 0, - } + }; end return self.sources[event.key]; @@ -90,11 +94,14 @@ end function Perimeter.check(self, event) - event.record = self:record_load(event); - -- self.log:debug('[', event.key, '/', event.sequence, '] PERIMETER_CHECK - received: ', event.received_ip, ':', event.received_port, ', contacts: ', event.record.contact_count, ', since: ', self:format_date(event.record.contact_first), ', points: ', event.record.points); - + if not event or not event.key then + self.log:warning('[perimeter] PERIMETER_CHECK - no event/key'); + return; + end + + event.record = self:record_load(event); if event.record.banned <= self.ban_tries then - for check_name, check_points in pairs(self.checks) do + for check_name, check_points in pairs(self.checks[event.action]) do if self.checks_available[check_name] then local result = self.checks_available[check_name](self, event); if tonumber(result) then @@ -169,7 +176,7 @@ end function Perimeter.check_bad_headers(self, event) local points = nil; - for name, pattern in pairs(self.bad_headers) do + for name, pattern in pairs(self.bad_headers[event.action]) do local success, result = pcall(string.find, event[name], pattern); if success and result then self.log:info('[', event.key, '/', event.sequence, '] PERIMETER_BAD_HEADERS - ', name, '=', event[name], ' ~= ', pattern); diff --git a/misc/freeswitch/scripts/event/perimeter_defense.lua b/misc/freeswitch/scripts/event/perimeter_defense.lua index c93eb13..acdfa8d 100644 --- a/misc/freeswitch/scripts/event/perimeter_defense.lua +++ b/misc/freeswitch/scripts/event/perimeter_defense.lua @@ -29,16 +29,20 @@ end function PerimeterDefense.event_handlers(self) - return { CUSTOM = { + return { + CUSTOM = { ['sofia::pre_register'] = self.sofia_pre_register, ['sofia::register_attempt'] = self.sofia_register_attempt, ['sofia::register_failure'] = self.sofia_register_failure, - } } + }, + CHANNEL_HANGUP = { [true] = self.channel_hangup }, + }; end -function PerimeterDefense.to_record(self, event, class) +function PerimeterDefense.to_register_record(self, event, class) return { + action = 'register', class = class, key = event:getHeader('network-ip'), sequence = tonumber(event:getHeader('Event-Sequence')), @@ -50,7 +54,6 @@ function PerimeterDefense.to_record(self, event, class) to_user = event:getHeader('to-user'), to_host = event:getHeader('to-host'), user_agent = event:getHeader('user-agent'), - user_agent = event:getHeader('user-agent'), username = event:getHeader('username'), realm = event:getHeader('realm'), auth_result = event:getHeader('auth-result'), @@ -59,19 +62,53 @@ function PerimeterDefense.to_record(self, event, class) end +function PerimeterDefense.to_call_record(self, event, class) + return { + action = 'call', + class = class, + key = event:getHeader('Caller-Network-Addr'), + sequence = tonumber(event:getHeader('Event-Sequence')), + timestamp = tonumber(event:getHeader('Event-Date-Timestamp')), + received_ip = event:getHeader('Caller-Network-Addr'), + received_port = event:getHeader('variable_sip_network_port'), + hangup_cause = event:getHeader('Hangup-Cause'), + endpoint_disposition = event:getHeader('variable_endpoint_disposition'), + direction = event:getHeader('Call-Direction'), + destination_number = event:getHeader('Caller-Destination-Number'); + caller_id_name = event:getHeader('Caller-Caller-ID-Name'); + caller_id_number = event:getHeader('Caller-Caller-ID-Number'); + from_user = event:getHeader('variable_sip_from_user'), + from_host = event:getHeader('variable_sip_from_host'), + to_user = event:getHeader('variable_sip_to_user'), + to_host = event:getHeader('variable_sip_to_host'), + req_user = event:getHeader('variable_sip_req_user'), + req_host = event:getHeader('variable_sip_req_host'), + user_agent = event:getHeader('variable_sip_user_agent'), + username = event:getHeader('Caller-Username'), + contact = event:getHeader('variable_sip_contact_uri'), + }; +end + + function PerimeterDefense.sofia_pre_register(self, event) - local record = self:to_record(event, 'pre_register'); + local record = self:to_register_record(event, 'pre_register'); self.perimeter:check(record); end function PerimeterDefense.sofia_register_attempt(self, event) - local record = self:to_record(event, 'register_attempt'); + local record = self:to_register_record(event, 'register_attempt'); self.perimeter:check(record); end function PerimeterDefense.sofia_register_failure(self, event) - local record = self:to_record(event, 'register_failure'); + local record = self:to_register_record(event, 'register_failure'); + self.perimeter:check(record); +end + + +function PerimeterDefense.channel_hangup(self, event) + local record = self:to_call_record(event, 'channel_hangup'); self.perimeter:check(record); end |