hpfeeds 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 03b7575438eb4799c7d0b2e9a25795020f24c501
4
+ data.tar.gz: 931209087d6e02e8b34d73d14485e6277747bd46
5
+ SHA512:
6
+ metadata.gz: 24dd1cea9aa0de6f341ecce8a960c1ce8d857b60eb11606458fbbbc7afbcb72164753c86bdfad6daf2f8bb3877f5658c3dda0dec212c2e74366867e0bfed1530
7
+ data.tar.gz: a6db74ca3dc4808fbc72208c73a28c729af8d84e27c70e3877c5d306b3368932a0ecaa60adb344e2b8df4c6c2ac3a75a4617c9c660f21704b950c71141beff4c
@@ -0,0 +1,2 @@
1
+ == 0.1.0
2
+ First release
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Francesco Coda Zabetta
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,60 @@
1
+ # HPFeeds
2
+
3
+ This gem should be used to make easy to interact (publish, subscribe) with a [HPFeeds broker](https://redmine.honeynet.org/projects/hpfeeds/wiki).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'hpfeeds'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install hpfeeds
18
+
19
+ ## Usage
20
+
21
+ Here is a basic example:
22
+
23
+ ```ruby
24
+ require "hpfeeds"
25
+
26
+ def on_data(name, chan, payload)
27
+ puts "[%s] %s: %s" % [ chan, name, payload ]
28
+ # just an example here...
29
+ @hp.publish('channel', 'message')
30
+ end
31
+
32
+ def on_error(data)
33
+ STDERR.puts "ERROR: " + data.inspect
34
+ end
35
+
36
+ begin
37
+ @hp = HPFeeds::Client.new ({
38
+ host: hpfeeds_server_name_here,
39
+ port: 10000,
40
+ ident: 'XXXX',
41
+ secret: '123456'
42
+ })
43
+ channels = %w[ chan1 chan2 chanN ]
44
+ @hp.subscribe(*channels)
45
+ @hp.run(method(:on_data), method(:on_error))
46
+
47
+ rescue => e
48
+ puts "Exception: #{e}"
49
+ ensure
50
+ @hp.close if @hp
51
+ end
52
+ ```
53
+
54
+ ## Contributing
55
+
56
+ 1. Fork it
57
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
58
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
59
+ 4. Push to the branch (`git push origin my-new-feature`)
60
+ 5. Create new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/clean'
@@ -0,0 +1,7 @@
1
+ require 'hpfeeds/version'
2
+
3
+ module HPFeeds
4
+ autoload :Client, 'hpfeeds/client'
5
+ autoload :Exception, 'hpfeeds/exception'
6
+ autoload :Decoder, 'hpfeeds/decoder'
7
+ end
@@ -0,0 +1,149 @@
1
+ require 'logger'
2
+ require 'socket'
3
+
4
+ module HPFeeds
5
+ OP_ERROR = 0
6
+ OP_INFO = 1
7
+ OP_AUTH = 2
8
+ OP_PUBLISH = 3
9
+ OP_SUBSCRIBE = 4
10
+
11
+ BUFSIZE = 16384
12
+ HEADERSIZE = 5
13
+
14
+ class Client
15
+ def initialize(options)
16
+ @host = options[:host]
17
+ @port = options[:port] || 10000
18
+ @ident = options[:ident]
19
+ @secret = options[:secret]
20
+
21
+ @timeout = options[:timeout] || 3
22
+ @reconnect = options[:reconnect] || true
23
+ @sleepwait = options[:sleepwait] || 20
24
+
25
+ @connected = false
26
+ @stopped = false
27
+
28
+ @decoder = Decoder.new
29
+ @logger = Logger.new($stdout)
30
+ @logger.level = Logger::INFO
31
+
32
+ tryconnect
33
+ end
34
+
35
+ def tryconnect
36
+ loop do
37
+ begin
38
+ connect()
39
+ break
40
+ rescue => e
41
+ @logger.warn("#{e.class} caugthed while connecting: #{e}. Reconnecting in #{@sleepwait} seconds...")
42
+ sleep(@sleepwait)
43
+ end
44
+ end
45
+ end
46
+
47
+ def connect
48
+ @socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
49
+ begin
50
+ @logger.debug("connecting #{@host}:#{@port}")
51
+ sockaddr = Socket.pack_sockaddr_in( @port, @host )
52
+ @socket.connect(sockaddr)
53
+ rescue => e
54
+ raise Exception.new("Could not connect to broker: #{e}.")
55
+ end
56
+ @logger.debug("waiting for data")
57
+ header = recv_timeout(HEADERSIZE)
58
+ opcode, len = @decoder.parse_header(header)
59
+ @logger.debug("received header, opcode = #{opcode}, len = #{len}")
60
+
61
+ if opcode == OP_INFO
62
+ data = recv_timeout(len)
63
+ @logger.debug("received data = #{data}")
64
+ name, rand = @decoder.parse_info(data)
65
+ @logger.debug("received INFO, name = #{name}, rand = #{rand}")
66
+ @brokername = name
67
+ auth = @decoder.msg_auth(rand, @ident, @secret)
68
+ @socket.send(auth, 0)
69
+ else
70
+ raise Exception('Expected info message at this point.')
71
+ end
72
+ @logger.info("connected to #{@host}, port #{@port}")
73
+ @connected = true
74
+ # set keepalive
75
+ @socket.setsockopt(Socket::Option.bool(:INET, :SOCKET, :KEEPALIVE, true))
76
+ end
77
+
78
+ def subscribe(*channels)
79
+ for c in channels
80
+ @logger.info("subscribing to #{c}")
81
+ message = @decoder.msg_subscribe(@ident, c)
82
+ @socket.send(message, 0)
83
+ end
84
+ end
85
+
86
+ def publish(data, *channels)
87
+ for c in channels
88
+ @logger.info("publish to #{c}: #{data}")
89
+ message = @decoder.msg_publish(@ident, c, data)
90
+ @socket.send(message, 0)
91
+ end
92
+ end
93
+
94
+ def stop
95
+ @stopped = true
96
+ end
97
+
98
+ def close
99
+ begin
100
+ @logger.debug("Closing socket")
101
+ @socket.close
102
+ rescue => e
103
+ @logger.warn("Socket exception when closing: #{e}")
104
+ end
105
+ end
106
+
107
+ def run(message_callback, error_callback)
108
+ begin
109
+ while !@stopped
110
+ while @connected
111
+ header = @socket.recv(HEADERSIZE)
112
+ if header.empty?
113
+ @connected = false
114
+ break
115
+ end
116
+ opcode, len = @decoder.parse_header(header)
117
+ @logger.debug("received header, opcode = #{opcode}, len = #{len}")
118
+ data = @socket.recv(len)
119
+ @logger.debug("received #{data.length} bytes of data")
120
+ if opcode == OP_ERROR
121
+ error_callback.call(data)
122
+ elsif opcode == OP_PUBLISH
123
+ name, chan, payload = @decoder.parse_publish(data)
124
+ @logger.info("received #{payload.length} bytes of data from #{name} on channel #{chan}")
125
+ message_callback.call(name, chan, payload)
126
+ end
127
+ end
128
+ @logger.debug("Lost connection, trying to connect again...")
129
+ tryconnect
130
+ end
131
+
132
+ rescue => e
133
+ message = "#{e.class} caugthed in main loop: #{e}\n"
134
+ message += e.backtrace.join("\n")
135
+ @logger.error(message)
136
+ end
137
+ end
138
+
139
+ private
140
+ def recv_timeout(len=BUFSIZE)
141
+ if IO.select([@socket], nil, nil, @timeout)
142
+ @socket.recv(len)
143
+ else
144
+ raise Exception.new("Connection receive timeout.")
145
+ end
146
+ end
147
+
148
+ end
149
+ end
@@ -0,0 +1,49 @@
1
+ require 'digest/sha1'
2
+
3
+ module HPFeeds
4
+ class Decoder
5
+
6
+ def parse_header(header)
7
+ raise Exception.new("Malformed header") if header.length < 5
8
+ len = header[0,4].unpack("l>")[0]
9
+ op = header[4,1].unpack("C")[0]
10
+ return op, len
11
+ end
12
+
13
+ def parse_info(data)
14
+ len = data[0,1].unpack("C")[0]
15
+ raise Exception.new("Malformed data") if data.length <= len
16
+ name = data[1,len]
17
+ rand = data[(1+len)..-1]
18
+ return name, rand
19
+ end
20
+
21
+ def parse_publish(data)
22
+ len = data[0,1].unpack("C")[0]
23
+ name = data[1,len]
24
+ len2 = data[(1+len),1].ord
25
+ chan = data[(1+len+1),len2]
26
+ payload = data[(1+len+1+len2)..-1]
27
+ return name, chan, payload
28
+ end
29
+
30
+ def msg_auth(rand, ident, secret)
31
+ mac = Digest::SHA1.digest(rand + secret)
32
+ msg_hdr(OP_AUTH, [ident.length].pack("C") + ident + mac)
33
+ end
34
+
35
+ def msg_subscribe(ident, chan)
36
+ msg_hdr(OP_SUBSCRIBE, [ident.length].pack("C") + ident + chan)
37
+ end
38
+
39
+ def msg_publish(ident, chan, msg)
40
+ msg_hdr(OP_PUBLISH, [ident.length].pack("C") + ident + [chan.length].pack("C") + chan + msg)
41
+ end
42
+
43
+ private
44
+
45
+ def msg_hdr(op, data)
46
+ [5+data.length].pack("l>") + [op].pack("C") + data
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ module HPFeeds
2
+ class Exception < RuntimeError; end
3
+ end
@@ -0,0 +1,3 @@
1
+ module HPFeeds
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hpfeeds
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Francesco Coda Zabetta
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-04-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Ruby client for HPFeeds protocol
42
+ email:
43
+ - francesco.codazabetta@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - lib/hpfeeds/exception.rb
49
+ - lib/hpfeeds/decoder.rb
50
+ - lib/hpfeeds/client.rb
51
+ - lib/hpfeeds/version.rb
52
+ - lib/hpfeeds.rb
53
+ - LICENSE.txt
54
+ - Rakefile
55
+ - README.md
56
+ - CHANGELOG.md
57
+ homepage: https://github.com/vicvega/hpfeeds-ruby
58
+ licenses:
59
+ - MIT
60
+ metadata: {}
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubyforge_project:
77
+ rubygems_version: 2.0.3
78
+ signing_key:
79
+ specification_version: 4
80
+ summary: Ruby client for HPFeeds protocol
81
+ test_files: []