netcrawl 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ gems
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # Netcrawl
2
+ Given snmp community and single device, crawls the network via discovering
3
+ LLDP/CDP neighbours, while producing list or dot file (for graphviz digraphs)
4
+
5
+ ## Install
6
+ % gem install netcrawl
7
+
8
+ ## Use
9
+ % netcrawl --graphiz router.example.com
10
+
11
+ ## Command line
12
+ ```
13
+ Usage: netcrawl [options] hostname
14
+ -g, --graphviz dot output use 'dot -Tpng -o map.png map.dot'
15
+ -l, --list list nodes
16
+ -j, --json json output
17
+ -y, --yaml yaml output
18
+ -a, --hash hash/associative array output
19
+ -r, --resolve resolve addresses to names
20
+ -p, --purge remove peers not in configured CIDR
21
+ -c, --community SNMP community to use
22
+ -d, --debug turn debugging on
23
+ -h, --help Display this help message.
24
+
25
+ ```
26
+ * graphiz - graphis (dot) output
27
+ * list - list nodes found
28
+ * json - json output
29
+ * yaml - yaml output
30
+ * hash - ruby hash output
31
+ * resolve - resolve IP addresses
32
+ * purge - remove non-cidr matching peers from output
33
+ * community - sets snmp community
34
+ * debug - turn on debugging
35
+
36
+ ## Config
37
+ ```
38
+ ---
39
+ use:
40
+ - LLDP
41
+ - CDP
42
+ poll:
43
+ - 192.0.2.0/24
44
+ snmp:
45
+ community: public
46
+ timeout: 1
47
+ retries: 2
48
+ bulkrows: 35
49
+ dot:
50
+ bothlinks: true
51
+ color:
52
+ - - cpe
53
+ - gold
54
+ - - -sw
55
+ - blue
56
+ - - -pe
57
+ - red
58
+ - - ' -p'
59
+ - yellow
60
+ dns:
61
+ afi:
62
+ log: STDERR
63
+ debug: false
64
+ namemap:
65
+ - - -re\d+
66
+ - ''
67
+ - - (.*(?<!as23456.net)$)
68
+ - \1.as23456.net
69
+ ```
70
+
71
+ * use - methods to use for crawling
72
+ * poll - cidrs to allow snmp for
73
+ * snmp community - snmp community to use
74
+ * snmp timout - snmp timout in seconds
75
+ * snmp retries - snmp retries count
76
+ * snmp bulkrows - snmp row count for bulkget
77
+ * dot bothlinks - show a-b and b-a link
78
+ * dot color - regexp to color, first hit used
79
+ * dns afi - ipv4/ipv6 or nil
80
+ * log - STDERR/STDOUT or file
81
+ * debug - debugging
82
+ * namemap - map (LLDP) name to FQDN (JunOS does not give domain)
83
+
84
+ ## Library use
85
+ require 'netcrawl'
86
+ output = NetCrawl.new.crawl('192.0.2.1').to_hash
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ begin
2
+ require 'rake/testtask'
3
+ require 'bundler'
4
+ Bundler.setup
5
+ rescue LoadError
6
+ warn 'bunler missing'
7
+ exit 42
8
+ end
9
+
10
+ gemspec = eval(File.read(Dir['*.gemspec'].first))
11
+ file = [gemspec.name, gemspec.version].join('-') + '.gem'
12
+
13
+ desc 'Validate gemspec'
14
+ task :gemspec do
15
+ gemspec.validate
16
+ end
17
+
18
+ desc 'Run minitest'
19
+ task :test do
20
+ Rake::TestTask.new do |t|
21
+ t.libs.push "lib"
22
+ t.test_files = FileList['spec/*_spec.rb']
23
+ t.verbose = true
24
+ end
25
+ end
26
+
27
+ desc 'Build gem'
28
+ task :build do
29
+ system "gem build #{gemspec.name}.gemspec"
30
+ FileUtils.mkdir_p 'gems'
31
+ FileUtils.mv file, 'gems'
32
+ end
33
+
34
+ desc 'Install gem'
35
+ task :install => :build do
36
+ system "sudo -E sh -c \'umask 022; gem install gems/#{file}\'"
37
+ end
38
+
39
+ desc 'Remove gems'
40
+ task :clean do
41
+ FileUtils.rm_rf 'gems'
42
+ end
43
+
44
+ desc 'Push to rubygems'
45
+ task :push do
46
+ system "gem push gems/#{file}"
47
+ end
data/bin/netcrawl ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'netcrawl/cli'
5
+ puts NetCrawl::CLI.new.run
6
+ rescue => error
7
+ warn "#{error}"
8
+ raise if NetCrawl::CFG.debug
9
+ end
data/lib/netcrawl.rb ADDED
@@ -0,0 +1,63 @@
1
+ require_relative 'netcrawl/config'
2
+ class NetCrawl
3
+ class NetCrawlError < StandardError; end
4
+ class MethodNotFound < NetCrawlError; end
5
+ attr_reader :hosts
6
+
7
+ # @param [String] host host to start crawl from
8
+ # @return [NetCrawl::Output]
9
+ def crawl host
10
+ recurse host
11
+ Output.new @hosts, @poll
12
+ end
13
+
14
+ # @param [String] host host to get list of peers from
15
+ # @return [Array] list of peers seen connected to host
16
+ def get host
17
+ peers = []
18
+ @methods.each do |method|
19
+ peers += method.send(:get, host)
20
+ end
21
+ peers.uniq
22
+ end
23
+
24
+ # Given string of IP address, recurses through peers seen and populates @hosts hash
25
+ # @param [String] host host to start recurse from
26
+ # @return [void]
27
+ def recurse host
28
+ peers = get host
29
+ @hosts[host] = peers
30
+ peers.each do |peer|
31
+ next if @hosts.has_key? peer
32
+ next unless @poll.include? peer
33
+ crawl peer
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def initialize
40
+ @methods = []
41
+ @hosts = {}
42
+ @poll = PollMap.new
43
+ CFG.use.each do |method|
44
+ begin
45
+ method = File.basename method.to_s
46
+ file = 'netcrawl/method/' + method.downcase
47
+ require_relative file
48
+ @methods.push NetCrawl.const_get(method)
49
+ rescue NameError, LoadError => error
50
+ raise MethodNotFound, "unable to find method '#{method}'"
51
+ end
52
+ end
53
+ end
54
+
55
+
56
+ end
57
+ require_relative 'netcrawl/pollmap'
58
+ require_relative 'netcrawl/namemap'
59
+ require_relative 'netcrawl/pollmap'
60
+ require_relative 'netcrawl/method/cdp'
61
+ require_relative 'netcrawl/method/lldp'
62
+ require_relative 'netcrawl/dns'
63
+ require_relative 'netcrawl/output'
Binary file
@@ -0,0 +1,59 @@
1
+ require_relative '../netcrawl'
2
+ require 'slop'
3
+
4
+ class NetCrawl
5
+ class CLI
6
+ class MissingHost < NetCrawlError; end
7
+ class NoConfig < NetCrawlError; end
8
+
9
+ def run
10
+ output = NetCrawl.new.crawl @host
11
+ output.clean if @opts[:purge]
12
+ output.resolve if @opts[:resolve]
13
+ if @opts[:graphviz]
14
+ output.to_dot
15
+ elsif @opts[:list]
16
+ output.to_list
17
+ elsif @opts[:json]
18
+ output.to_json
19
+ elsif @opts[:yaml]
20
+ output.to_yaml
21
+ else
22
+ output.to_hash
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def initialize
29
+ if Config.system.empty? and Config.user.empty?
30
+ Config.user = Config.default
31
+ Config.save :user
32
+ raise NoConfig, 'edit ~/.config/netcrawl/config'
33
+ end
34
+ @opts = opt_parse
35
+ args = @opts.parse
36
+ @host = DNS.getip args.shift
37
+ CFG.snmp.community = @opts[:community] if @opts[:community]
38
+ CFG.debug = true if @opts[:debug]
39
+ raise MissingHost, 'no hostname given as argument' unless @host
40
+ end
41
+
42
+
43
+ def opt_parse
44
+ opts = Slop.parse(:help=>true) do
45
+ banner 'Usage: netcrawl [options] hostname'
46
+ on 'g', 'graphviz', 'dot output use \'dot -Tpng -o map.png map.dot\''
47
+ on 'l', 'list', 'list nodes'
48
+ on 'j', 'json', 'json output'
49
+ on 'y', 'yaml', 'yaml output'
50
+ on 'a', 'hash', 'hash/associative array output'
51
+ on 'r', 'resolve', 'resolve addresses to names'
52
+ on 'p', 'purge', 'remove peers not in configured CIDR'
53
+ on 'c=', 'community', 'SNMP community to use'
54
+ on 'd', 'debug', 'turn debugging on'
55
+ end
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,37 @@
1
+ require 'asetus'
2
+ require 'logger'
3
+ class NetCrawl
4
+ Config = Asetus.new :name=>'netcrawl', :load=>false
5
+ Config.default.use = %w(LLDP CDP)
6
+ Config.default.poll = [ # addresses accepted for polling
7
+ '192.0.2.0/24',
8
+ '198.51.100.0/24',
9
+ '0.0.0.0/0',
10
+ ]
11
+ Config.default.snmp.community = 'public'
12
+ Config.default.snmp.timeout = 1
13
+ Config.default.snmp.retries = 2
14
+ Config.default.snmp.bulkrows = 35 # 1500B packet should fit about 50 :cdpCacheAddress rows
15
+ Config.default.dot.bothlinks = false # keep both a-b and b-a links
16
+ Config.default.dot.color = [ # regexp of host => color
17
+ [ 'cpe', 'gold' ],
18
+ [ '-sw', 'blue' ],
19
+ [ '-pe', 'red' ],
20
+ [' -p', 'yellow' ],
21
+ ]
22
+ Config.default.dns.afi = nil # could be 'ipv4' or 'ipv6'
23
+ Config.default.log = 'STDERR'
24
+ Config.default.debug = false
25
+ Config.default.namemap = [ # regexp match+sub of hostname (needed for LLDP)
26
+ ['-re\d+', ''],
27
+ ['^KILLME(.*(?<!my.domain.com)$)', '\1.my.domain.com'], #adds missing domain name
28
+ ]
29
+ Config.load
30
+ CFG = Config.cfg
31
+ log = CFG.log
32
+ log = STDERR if log == 'STDERR'
33
+ log = STDOUT if log == 'STDOUT'
34
+ Log = Logger.new log
35
+ Log.level = Logger::INFO
36
+ Log.level = Logger::DEBUG if CFG.debug
37
+ end
@@ -0,0 +1,53 @@
1
+ require 'resolv'
2
+ class NetCrawl
3
+ class Resolve
4
+
5
+ # @param [String] name DNS name which we try to resolve to IP
6
+ # @return [String, nil] string if name resolves to IP, otherwise nil
7
+ def getip name
8
+ if @cacheip.has_key? name
9
+ @cacheip[name]
10
+ else
11
+ ip = nil
12
+ begin
13
+ if CFG.dns.afi == 'ipv4'
14
+ ip = Resolv::DNS.new.getresource(name, Resolv::DNS::Resource::IN::A).address
15
+ elsif CFG.dns.afi == 'ipv6'
16
+ ip = Resolv::DNS.new.getresource(name, Resolv::DNS::Resource::IN::AAAA).address
17
+ else
18
+ ip = Resolv.getaddress name
19
+ end
20
+ rescue => error
21
+ Log.debug "DNS resolution for '#{name}' raised error '#{error.class}' with message '#{error.message}'"
22
+ return nil
23
+ end
24
+ @cacheip[name] = ip
25
+ end
26
+ end
27
+
28
+ # @param [String] ip DNS IP which we try to resolve to name
29
+ # @return [String] name if it resolves, ip otherwise
30
+ def getname ip
31
+ if @cachename.has_key? ip
32
+ @cachename[ip]
33
+ else
34
+ name = nil
35
+ begin
36
+ name = Resolv.getname ip
37
+ rescue => error
38
+ Log.debug "DNS resolution for '#{ip}' raised error '#{error.class}' with message '#{error.message}'"
39
+ name = ip
40
+ end
41
+ @cachename[ip] = name
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def initialize
48
+ @cacheip = {}
49
+ @cachename = {}
50
+ end
51
+ end
52
+ DNS = Resolve.new
53
+ end
@@ -0,0 +1,33 @@
1
+ require_relative '../snmp'
2
+ class NetCrawl
3
+ class CDP
4
+ OID = {
5
+ # http://tools.cisco.com/Support/SNMP/do/BrowseOID.do?local=en&translate=Translate&objectInput=1.3.6.1.4.1.9.9.23.1.2.1.1
6
+ :cdpCacheAddress => '1.3.6.1.4.1.9.9.23.1.2.1.1.4',
7
+ :cdpCacheDeviceId => '1.3.6.1.4.1.9.9.23.1.2.1.1.6',
8
+ }
9
+
10
+ # @param [String] host host to query
11
+ # @return [Hash] neighbor information
12
+ def self.get host
13
+ cdp = new(host)
14
+ cdp.peers
15
+ end
16
+
17
+ def peers
18
+ @snmp.bulkwalk(OID[:cdpCacheAddress]).map do |vb|
19
+ vb.as_ip
20
+ end
21
+ rescue SNMP::NoResponse
22
+ []
23
+ end
24
+
25
+ private
26
+
27
+ def initialize host
28
+ @snmp = SNMP.new host
29
+ end
30
+
31
+
32
+ end
33
+ end
@@ -0,0 +1,35 @@
1
+ require_relative '../snmp'
2
+ class NetCrawl
3
+ class LLDP
4
+ include NameMap
5
+ OID = {
6
+ # http://standards.ieee.org/getieee802/download/802.1AB-2009.pdf
7
+ :lldpRemChassisIdSubtype => '1.0.8802.1.1.2.1.4.1.1.4', # CSCO and JNPR use 4 (MAC address) rendering ChassisID useless
8
+ :lldpRemChassisId => '1.0.8802.1.1.2.1.4.1.1.5',
9
+ :lldpRemSysName => '1.0.8802.1.1.2.1.4.1.1.9',
10
+ }
11
+
12
+ # @param [String] host host to query
13
+ # @return [Hash] neighbor information
14
+ def self.get host
15
+ lldp = new(host)
16
+ lldp.peers
17
+ end
18
+
19
+ def peers
20
+ @snmp.bulkwalk(OID[:lldpRemSysName]).map do |vb|
21
+ DNS.getip namemap(vb.value)
22
+ end.compact
23
+ rescue SNMP::NoResponse
24
+ []
25
+ end
26
+
27
+ private
28
+
29
+ def initialize host
30
+ @snmp = SNMP.new host
31
+ end
32
+
33
+
34
+ end
35
+ end
@@ -0,0 +1,12 @@
1
+ class NetCrawl
2
+ module NameMap
3
+ def namemap name_org
4
+ name = name_org.dup
5
+ CFG.namemap.each do |match, replace|
6
+ re = Regexp.new match
7
+ name = name.sub re, replace
8
+ end
9
+ name
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,72 @@
1
+ class NetCrawl
2
+ class Output
3
+ attr_reader :iphash, :namehash, :hash
4
+
5
+ # @return [String] pretty print of hash
6
+ def to_hash
7
+ require 'pp'
8
+ out = ''
9
+ PP.pp @hash, out
10
+ out
11
+ end
12
+
13
+ # @return [String] yaml of hosts and peers found
14
+ def to_yaml
15
+ require 'yaml'
16
+ YAML.dump @hash
17
+ end
18
+
19
+ # @return [String] json of hosts and peers found
20
+ def to_json
21
+ require 'json'
22
+ JSON.pretty_generate @hash
23
+ end
24
+
25
+ # @return [Array] of nodes found
26
+ def to_list
27
+ nodes = []
28
+ @hash.each do |host, peers|
29
+ nodes << host
30
+ nodes << peers
31
+ end
32
+ nodes.flatten.uniq.sort
33
+ end
34
+
35
+ # resolves ip addresses and changes @hash to point to the resolved hash
36
+ # @return [void]
37
+ def resolve
38
+ @namehash = {}
39
+ @iphash.each do |host, peers|
40
+ host = DNS.getname host
41
+ @namehash[host] = []
42
+ peers.each do |peer|
43
+ @namehash[host].push DNS.getname(peer)
44
+ end
45
+ end
46
+ @hash = @namehash
47
+ end
48
+
49
+ # remove peers not matchin configured CIDR
50
+ def clean
51
+ @hash.each do |host, peers|
52
+ peers = peers.delete_if{|peer|not @pollmap.include? peer}
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def initialize hash, pollmap
59
+ @iphash = hash
60
+ @hash = @iphash
61
+ @pollmap = pollmap
62
+ end
63
+
64
+ def method_missing name, *args
65
+ raise NoMethodError, "invalid method #{name} for #{inspect}:#{self.class}" unless name.match(/to_.*/)
66
+ output = File.basename name[3..-1]
67
+ require_relative 'output/' + output
68
+ output = NetCrawl::Output.const_get output.capitalize
69
+ output.send :output, self
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,53 @@
1
+ class NetCrawl
2
+ class Output
3
+ class Dot
4
+ INDENT = ' ' * 2
5
+ DEFAULT_COLOR = 'black'
6
+ def self.output output
7
+ new(output).to_s
8
+ end
9
+
10
+ def to_s
11
+ str = "graph NetCrawl {\n"
12
+ @output.to_list.each do |host|
13
+ str << INDENT + id(host) + "[color=\"#{color(host)}\"]\n"
14
+ str << INDENT + id(host) + "[label=\"#{host}\"]\n"
15
+ if @hash.has_key? host
16
+ @hash[host].each do |peer|
17
+ next if not CFG.dot.bothlinks and @connections.include?([peer, host].sort)
18
+ @connections << [peer, host].sort
19
+ str << INDENT + INDENT + id(host) + ' -- ' + id(peer) + "\n"
20
+ end
21
+ end
22
+ end
23
+ str << "}\n"
24
+ str
25
+ end
26
+
27
+ private
28
+
29
+ def initialize output
30
+ @output = output
31
+ @connections = []
32
+ @hash = @output.hash
33
+ end
34
+
35
+ def id host
36
+ host = host.gsub(/[-.]/, '_')
37
+ '_' + host
38
+ end
39
+
40
+ def color host
41
+ color = nil
42
+ CFG.dot.color.each do |re, clr|
43
+ if host.match re
44
+ color = clr
45
+ break
46
+ end
47
+ end
48
+ color or DEFAULT_COLOR
49
+ end
50
+ end
51
+ end
52
+ end
53
+
@@ -0,0 +1,13 @@
1
+ require 'ipaddr'
2
+ class NetCrawl
3
+ class PollMap
4
+ def initialize
5
+ @poll = CFG.poll.map do |cidr|
6
+ IPAddr.new cidr
7
+ end
8
+ end
9
+ def include? addr
10
+ @poll.any? { |cidr| cidr.include? addr }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,68 @@
1
+ require 'snmp'
2
+ class NetCrawl
3
+ class SNMP
4
+ class NoResponse < NetCrawlError; end
5
+ # Closes the SNMP connection
6
+ # @return [void]
7
+ def close
8
+ @snmp.close
9
+ end
10
+
11
+ # Gets one oid, return value
12
+ # @param [String] oid to get
13
+ # @return [SNMP::VarBind]
14
+ def get oid
15
+ mget([oid]).first
16
+ end
17
+
18
+ # Get multiple oids, return array of values
19
+ # @param [Array(String)] oids to get
20
+ # @return [SNMP::VarBindList]
21
+ def mget oids
22
+ snmp :get, oids
23
+ end
24
+
25
+ # Bulkwalk everything below root oid
26
+ # @param [String] root oid to start from
27
+ # @return [Array(SNMP::VarBind)]
28
+ def bulkwalk root
29
+ last, oid, results = false, root.dup, []
30
+ root = root.split('.').map{|chr|chr.to_i}
31
+ while not last
32
+ vbs = snmp(:get_bulk, 0, CFG.snmp.bulkrows, oid).varbind_list
33
+ vbs.each do |vb|
34
+ oid = vb.oid
35
+ (last = true; break) if not oid[0..root.size-1] == root
36
+ results.push vb
37
+ end
38
+ end
39
+ results
40
+ end
41
+
42
+ private
43
+
44
+ def initialize host, community=CFG.snmp.community, timeout=CFG.snmp.timeout, retries=CFG.snmp.retries
45
+ @host = host
46
+ @snmp = ::SNMP::Manager.new :Host=>@host, :Community=>community,
47
+ :Timeout=>timeout, :Retries=>retries,
48
+ :MibModules=>[]
49
+ end
50
+
51
+ def snmp cmd, *args
52
+ @snmp.send cmd, *args
53
+ rescue ::SNMP::RequestTimeout, Errno::EACCES => error
54
+ msg = "host '#{@host}' raised '#{error.class}' with message '#{error.message}' for method '#{cmd}' with args '#{args}'"
55
+ Log.warn msg
56
+ raise NoResponse, msg
57
+ end
58
+
59
+ end
60
+ end
61
+
62
+ module SNMP
63
+ class VarBind
64
+ def as_ip
65
+ SNMP::IpAddress.new(value).to_s
66
+ end
67
+ end
68
+ end
data/netcrawl.gemspec ADDED
@@ -0,0 +1,18 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'netcrawl'
3
+ s.version = '0.0.1'
4
+ s.platform = Gem::Platform::RUBY
5
+ s.authors = [ 'Saku Ytti' ]
6
+ s.email = %w( saku@ytti.fi )
7
+ s.homepage = 'http://github.com/ytti/netcrawl'
8
+ s.summary = 'lldp/cdp crawler'
9
+ s.description = 'given snmp community and one node crawls through the network to produce list/dot file'
10
+ s.rubyforge_project = s.name
11
+ s.files = `git ls-files`.split("\n")
12
+ s.executables = %w( netcrawl )
13
+ s.require_path = 'lib'
14
+
15
+ s.add_dependency 'snmp'
16
+ s.add_dependency 'slop'
17
+ s.add_dependency 'asetus'
18
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: netcrawl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Saku Ytti
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-03-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: snmp
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: slop
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: asetus
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: given snmp community and one node crawls through the network to produce
63
+ list/dot file
64
+ email:
65
+ - saku@ytti.fi
66
+ executables:
67
+ - netcrawl
68
+ extensions: []
69
+ extra_rdoc_files: []
70
+ files:
71
+ - .gitignore
72
+ - Gemfile
73
+ - README.md
74
+ - Rakefile
75
+ - bin/netcrawl
76
+ - lib/netcrawl.rb
77
+ - lib/netcrawl/.cli.rb.swp
78
+ - lib/netcrawl/cli.rb
79
+ - lib/netcrawl/config.rb
80
+ - lib/netcrawl/dns.rb
81
+ - lib/netcrawl/method/cdp.rb
82
+ - lib/netcrawl/method/lldp.rb
83
+ - lib/netcrawl/namemap.rb
84
+ - lib/netcrawl/output.rb
85
+ - lib/netcrawl/output/dot.rb
86
+ - lib/netcrawl/pollmap.rb
87
+ - lib/netcrawl/snmp.rb
88
+ - netcrawl.gemspec
89
+ homepage: http://github.com/ytti/netcrawl
90
+ licenses: []
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ segments:
102
+ - 0
103
+ hash: -152408900674429923
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ segments:
111
+ - 0
112
+ hash: -152408900674429923
113
+ requirements: []
114
+ rubyforge_project: netcrawl
115
+ rubygems_version: 1.8.25
116
+ signing_key:
117
+ specification_version: 3
118
+ summary: lldp/cdp crawler
119
+ test_files: []