Skip to content

Instantly share code, notes, and snippets.

@peelman
Last active April 14, 2025 01:56
Show Gist options
  • Save peelman/257568d048c0a272f778ec8c0b861a7e to your computer and use it in GitHub Desktop.
Save peelman/257568d048c0a272f778ec8c0b861a7e to your computer and use it in GitHub Desktop.
Interface Traps

Interface Trap Script

Posted mostly for inspiration.

Installation

  1. Copy interface_trap.rb to /usr/local/bin (or wherever you store scripts on your system(s).
  2. Be sure the following Gems are installed: optparse, slack-notifier, snmp

Configuration

SNMPtt

/etc/snmp/snmptt.ini (Debian/Ubuntu Location, YMMV)

[TrapFiles]
# A list of snmptt.conf files (this is NOT the snmptrapd.conf file).  The COMPLETE path 
# and filename.  Ex: '/etc/snmp/snmptt.conf'
# /etc/snmp/traps.d/ietf-ifmib.conf
#
snmptt_conf_files = <<END
/etc/snmp/traps.d/ietf-ifmib.conf
END

/etc/snmp/traps.d/ietf-ifmib.conf

EVENT linkDown .1.3.6.1.6.3.1.1.5.3 "Status Events" Normal
FORMAT A linkDown trap signifies that the SNMP entity, acting in $*
EXEC /usr/local/bin/interface_trap.rb -h "$aA" -c <yourcommunitystring> -i $1 -a $2 -o $3
SDESC
Variables:
  1: ifIndex
  2: ifAdminStatus
  3: ifOperStatus
EDESC

EVENT linkUp .1.3.6.1.6.3.1.1.5.4 "Status Events" Normal
FORMAT A linkUp trap signifies that the SNMP entity, acting in an $*
NODES /etc/snmp/trap-nodes/ietf-ifmib.conf
EXEC /usr/local/bin/interface_trap.rb -h "$aA" -c <yourcommunitystring> -i $1 -a $2 -o $3

SDESC
Variables:
  1: ifIndex
  2: ifAdminStatus
  3: ifOperStatus
EDESC

Sample output

image

#!/usr/bin/ruby
######################################################################################################
#
# Description:
# Handle SNMP Traps for IETF LinkUp and LinkDown
# * Post All Traps to Slack Channel provided by SLACK_WEBHOOK_URL
#
######################################################################################################
#
# Author: Nick Peelman
#
######################################################################################################
#
# Usage:
# interface_trap.rb -H <hostname> -c <community> -i <index> -a <admin-status> -o <oper-status>
# Parameters:
# * <hostname>: Hostname or IP that sent the trap
# * <community>: SNMP Community with Read privileges to the IF-MIB
# * <index>: the index of the interface that changed state
# * <admin-status>: the admin status as sent by the trap
# * <oper-status>: the oper status as sent by the trap
#
######################################################################################################
#
# Requirements
# * gem install slack-notifier
# * gem install snmp
#
######################################################################################################
require 'optparse'
require 'slack-notifier'
require 'snmp'
######################################################################################################
# CONFIGURATION Parameters
#
SLACK_WEBHOOK_URL = "<slack-webhook-url>"
SLACK_CHANNEL = "#port-notifications"
######################################################################################################
OID_IFDESCR = SNMP::ObjectName.new "1.3.6.1.2.1.2.2.1.2"
OID_IFALIAS = SNMP::ObjectName.new "1.3.6.1.2.1.31.1.1.1.18"
OID_IFADMIN = SNMP::ObjectName.new "1.3.6.1.2.1.2.2.1.7"
OID_IFOPER = SNMP::ObjectName.new "1.3.6.1.2.1.2.2.1.8"
OID_IFSPEED = SNMP::ObjectName.new "1.3.6.1.2.1.31.1.1.1.15"
OID_IFMTU = SNMP::ObjectName.new "1.3.6.1.2.1.2.2.1.4"
OID_SYSNAME = SNMP::ObjectName.new "1.3.6.1.2.1.1.5.0"
OID_ARRAY = [
OID_IFDESCR,
OID_IFALIAS,
OID_IFADMIN,
OID_IFOPER,
OID_IFSPEED,
OID_IFMTU,
OID_SYSNAME
]
OID_VALUES_IFSTATUS = {
1 => "Up",
2 => "Down",
3 => "Testing",
4 => "Unknown",
5 => "Dormant",
6 => "Not Present",
7 => "Lower Layer Down"
}
@sysname = ''
@ifdescr = ''
@ifalias = ''
@ifadminstatus = ''
@ifoperstatus = ''
@ifspeed
@ifmtu
def parse_args(args = {})
@print = args[:print].nil? ? true : args[:print]
@exit = args[:exit].nil? ? true : args[:exit]
# now, handle the arguments...
@opts = OptionParser.new
@opts.on("-h", "--host HOSTNAME", "Hostname or IP") do |h|
@hostname = h
end
@opts.on("-c", "--community COMMUNITY", "snmp community") do |c|
@community = c
end
@opts.on("-i", "--index INDEX", "ifIndex") do |i|
@ifindex = i
end
@opts.on("-a", "--admin STATUS", "ifAdminStatus") do |a|
@ifadminstatus = a
end
@opts.on("-o", "--oper STATUS", "ifOperStatus") do |o|
@ifoperstatus = o
end
@opts.on("-d", "--debug", "print output, don't send to slack") do |d|
@debug = true
end
@opts.on_tail("-h", "--help", "Show this message") do
puts @opts
exit
end
@opts.parse!
end
def number_to_ifstatus(number)
if number.to_i == 0
return "Down"
elsif number.to_i == 1
return "Up"
else
return "Unknown"
end
end
UNITS = ['Kbps', 'Mbps', 'Gbps', 'Tbps', 'Pbps', 'Ebps', 'Zbps', 'Ybps']
def safe_vb_to_int(number, safe = 0)
Integer(number) rescue safe
end
def number_to_human_bps(number)
pos = 1
n = number
while (n > 999)
n = n/1000
pos = pos+1
end
return "#{n}#{UNITS[pos]}"
end
def fetch_oids(host, community)
SNMP::Manager.open(host: host, community: community) do |manager|
response = manager.get(OID_ARRAY)
response.each_varbind do |vb|
case vb.name.to_str
when OID_SYSNAME.to_str
@sysname = vb.value
break
when OID_IFDESCR.to_str
next if vb.value.class === SNMP::NoSuchInstance
@ifdescr = vb.value
when OID_IFALIAS.to_str
next if vb.value.class === SNMP::NoSuchInstance
@ifalias = vb.value
when OID_IFADMIN.to_str
@ifadminstatus = safe_vb_to_int(vb.value, 6)
when OID_IFOPER.to_str
@ifoperstatus = safe_vb_to_int(vb.value, 6)
when OID_IFSPEED.to_str
@ifspeed = number_to_human_bps(safe_vb_to_int(vb.value, 0))
when OID_IFMTU.to_str
@ifmtu = safe_vb_to_int(vb.value, 0)
else
puts "Error: unknown VarBind returned: #{vb}"
end
end
end
end
def send_slack_message(message, attachments)
notifier = Slack::Notifier.new SLACK_WEBHOOK_URL
notifier.post({text:"#{message}", attachments: attachments})
end
def get_address_array(peer_group)
addresses = []
peer_group.each_value do |v|
addresses << v.fetch(:address)
end
return addresses
end
def ip_to_peer_name(ip_address, peer_group)
peer_group.each do |k,v|
return k if v.fetch(:address) == ip_address
end
return nil
end
def main
parse_args
@sysname = @hostname
@ifdescr = ''
@ifalias = ''
@ifadminstatus = ''
@ifoperstatus = ''
@ifspeed = ''
@ifmtu = ''
@msgcolor = "#cccccc"
OID_IFDESCR.push(@ifindex)
OID_IFALIAS.push(@ifindex)
OID_IFOPER.push(@ifindex)
OID_IFADMIN.push(@ifindex)
OID_IFSPEED.push(@ifindex)
OID_IFMTU.push(@ifindex)
fetch_oids(@hostname, @community)
case @ifoperstatus
when 1
message_head = ":white_check_mark: Port Up"
@msgcolor = 'good'
when 2
message_head = ":x: Port Down"
@msgcolor = 'danger'
when 3
message_head = ":construction: Port Testing"
@msgcolor ='warning'
when 4
message_head = ":game_die: Port Unknown"
@msgcolor = 'warning'
when 5
message_head = ":mountain: Port Dormant"
@msgcolor = 'warning'
when 6
message_head = ":ghost: Not Present"
@msgcolor = 'warning'
when 7
message_head = ":x: Lower Layer Down"
@msgcolor = 'warning'
else
message_head = ":interrobang: Unknown Oper Status"
@msgcolor = 'warning'
end
if (@ifalias.match(/((G|g)enerator)|(.*#?trap-?disable.*)|(.*#?disable-?trap.*)|(.*#?no-?trap.*)/))
puts "Ignoring Trap due to ifAlias: \"#{@ifalias}\""
exit
end
ifindex_friendly = "Index: #{@ifindex}"
message = "#{message_head}: #{@sysname} [#{@ifalias.empty? ? @ifdescr : @ifalias}]"
attachments = [{
'color': @msgcolor,
'fallback': message,
'fields': [
{
'title': "Device",
'value': "#{@sysname}",
'short': true
},
{
'title': "Description",
'value': "#{@ifalias.empty? ? @ifdescr : @ifalias}",
'short': true
},
{
'title': "Details",
'value': "#{@ifalias.empty? ? ifindex_friendly : @ifdescr}",
'short': false
},
{
'title': "Admin Status",
'value': "#{OID_VALUES_IFSTATUS[@ifadminstatus]}",
'short': true
},
{
'title': "Oper Status",
'value': "#{OID_VALUES_IFSTATUS[@ifoperstatus]}",
'short': true
},
{
'title': "Speed",
'value': "#{@ifspeed}",
'short': true
},
{
'title': "MTU",
'value': "#{@ifmtu}",
'short': true
},
]
}]
send_slack_message('', attachments) unless @debug
puts attachments if @debug
end
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment