netlink 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +54 -0
- data/.solargraph.yml +23 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +28 -0
- data/LICENSE.txt +21 -0
- data/README.md +37 -0
- data/Rakefile +29 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/netlink/addrinfo.rb +69 -0
- data/lib/netlink/nlmsghdr.rb +69 -0
- data/lib/netlink/socket.rb +138 -0
- data/lib/netlink/version.rb +5 -0
- data/lib/netlink.rb +64 -0
- data/netlink.gemspec +38 -0
- data/sig/netlink.rbs +4 -0
- metadata +64 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ca60658b31b777fad08d777e1fcd306ae116f4a41451f5ecac10c9f559dc2cc0
|
4
|
+
data.tar.gz: 14cd35e02048ed8ccfcbf9be64090d4ba63628259bd05c4e82206788cc3bc009
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5c8e244f5ba3575d92f44b0713a4000d82699bdd920afbbdbd1b39b7a1aa102853bc59c9466cd90b5432235c567a8484082e2edb4fa6aa1d34fc8fd2d6ff10e8
|
7
|
+
data.tar.gz: f018b7f5ffff6773d3947497bc2c1c49141b198ac5702e4e4b77168b1a60a523b9141abdb591ae6da99e9db06376b721ecb24aca9fe250129ae5c66e706b83c6
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-performance
|
3
|
+
AllCops:
|
4
|
+
TargetRubyVersion: '2.7'
|
5
|
+
NewCops: enable
|
6
|
+
Exclude:
|
7
|
+
- .git/**/*
|
8
|
+
- spec/**/*
|
9
|
+
- vendor/**/*
|
10
|
+
Gemspec/RequireMFA:
|
11
|
+
Enabled: false
|
12
|
+
Layout/LineLength:
|
13
|
+
Enabled: false
|
14
|
+
Layout/SpaceAroundEqualsInParameterDefault:
|
15
|
+
EnforcedStyle: no_space
|
16
|
+
Lint/AmbiguousOperatorPrecedence:
|
17
|
+
Enabled: false
|
18
|
+
Lint/EmptyWhen:
|
19
|
+
Enabled: false
|
20
|
+
Lint/Void:
|
21
|
+
Enabled: false
|
22
|
+
Metrics/AbcSize:
|
23
|
+
Max: 20
|
24
|
+
Metrics/ClassLength:
|
25
|
+
Max: 200
|
26
|
+
Metrics/MethodLength:
|
27
|
+
Max: 20
|
28
|
+
Metrics/ParameterLists:
|
29
|
+
MaxOptionalParameters: 4
|
30
|
+
Style/AccessModifierDeclarations:
|
31
|
+
Enabled: false
|
32
|
+
Style/AsciiComments:
|
33
|
+
Enabled: false
|
34
|
+
Style/Documentation:
|
35
|
+
# Too many false positives!
|
36
|
+
Enabled: false
|
37
|
+
Style/Encoding:
|
38
|
+
Enabled: false
|
39
|
+
Style/EvalWithLocation:
|
40
|
+
Enabled: false
|
41
|
+
Style/FormatString:
|
42
|
+
EnforcedStyle: percent
|
43
|
+
Style/FormatStringToken:
|
44
|
+
MaxUnannotatedPlaceholdersAllowed: 3
|
45
|
+
Style/PerlBackrefs:
|
46
|
+
Enabled: false
|
47
|
+
Style/RedundantSelf:
|
48
|
+
Enabled: false
|
49
|
+
Style/StructInheritance:
|
50
|
+
Enabled: false
|
51
|
+
Style/TrailingCommaInArrayLiteral:
|
52
|
+
Enabled: false
|
53
|
+
Style/TrailingCommaInHashLiteral:
|
54
|
+
Enabled: false
|
data/.solargraph.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
---
|
2
|
+
include:
|
3
|
+
- "**/*.rb"
|
4
|
+
exclude:
|
5
|
+
- spec/**/*
|
6
|
+
- test/**/*
|
7
|
+
- vendor/**/*
|
8
|
+
- ".bundle/**/*"
|
9
|
+
require: []
|
10
|
+
domains: []
|
11
|
+
reporters:
|
12
|
+
- rubocop
|
13
|
+
- require_not_found
|
14
|
+
- typecheck: strict
|
15
|
+
formatter:
|
16
|
+
rubocop:
|
17
|
+
cops: safe
|
18
|
+
except: []
|
19
|
+
only: []
|
20
|
+
extra_args: []
|
21
|
+
require_paths: []
|
22
|
+
plugins: []
|
23
|
+
max_files: 5000
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in netlink.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
group :development do
|
9
|
+
gem 'debase', '~>0.2'
|
10
|
+
gem 'ruby-debug-ide', '~> 0.7'
|
11
|
+
gem 'solargraph', '~>0.22', require: false
|
12
|
+
gem 'yard', '~>0.9', require: false
|
13
|
+
end
|
14
|
+
|
15
|
+
group :test do
|
16
|
+
gem 'rspec', '~> 3.0'
|
17
|
+
gem 'simplecov', require: false
|
18
|
+
end
|
19
|
+
|
20
|
+
group :development, :test do
|
21
|
+
gem 'rake'
|
22
|
+
end
|
23
|
+
|
24
|
+
group :rubocop do
|
25
|
+
gem 'rubocop', '~> 1.0', require: false
|
26
|
+
gem 'rubocop-performance', '~> 1.0', require: false
|
27
|
+
gem 'rubocop-rake', '~> 0.6', require: false
|
28
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2023 Sylvain Daubert
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Netlink
|
2
|
+
|
3
|
+
Ruby library to use Netlink sockets on Linux
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'netlink'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle install
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install netlink
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
## Development
|
26
|
+
|
27
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
28
|
+
|
29
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
30
|
+
|
31
|
+
## Contributing
|
32
|
+
|
33
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/netlink.
|
34
|
+
|
35
|
+
## License
|
36
|
+
|
37
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
7
|
+
t.rspec_opts = '-t ~sudo'
|
8
|
+
end
|
9
|
+
RSpec::Core::RakeTask.new('spec:sudo') do |t|
|
10
|
+
t.rspec_opts = '-t sudo'
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'rubocop/rake_task'
|
14
|
+
|
15
|
+
RuboCop::RakeTask.new
|
16
|
+
|
17
|
+
task default: %i[spec rubocop]
|
18
|
+
|
19
|
+
# rubocop:disable Lint/SuppressedException
|
20
|
+
begin
|
21
|
+
require 'yard'
|
22
|
+
|
23
|
+
YARD::Rake::YardocTask.new do |t|
|
24
|
+
t.files = ['lib/**/*.rb', '-', 'README.md', 'LICENSE.txt']
|
25
|
+
t.options = %w[--no-private]
|
26
|
+
end
|
27
|
+
rescue LoadError
|
28
|
+
end
|
29
|
+
# rubocop:enable Lint/SuppressedException
|
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'netlink'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
require 'forwardable'
|
5
|
+
|
6
|
+
module Netlink
|
7
|
+
# AddrInfo for {Socket}.
|
8
|
+
class Addrinfo
|
9
|
+
attr_reader :afamily, :pid, :groups
|
10
|
+
|
11
|
+
# @param [Array(String, Integer, Integer),Array(Integer, Integer, Integer),String] sockaddr array form should be compatible to the value of
|
12
|
+
# {Socket#addr}. The string should be struct sockaddr as generated by {{Socket.sockaddr_nl}}.
|
13
|
+
def initialize(sockaddr)
|
14
|
+
case sockaddr
|
15
|
+
when Array
|
16
|
+
init_from_array(sockaddr)
|
17
|
+
when String
|
18
|
+
init_from_string(sockaddr)
|
19
|
+
else
|
20
|
+
raise TypeError, 'sockaddr must be a String or an Array'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# returns the socket address as packed struct sockaddr string
|
25
|
+
# @return [String]
|
26
|
+
def to_sockaddr
|
27
|
+
Socket.sockaddr_nl(@pid, @groups)
|
28
|
+
end
|
29
|
+
alias to_s to_sockaddr
|
30
|
+
alias to_str to_sockaddr
|
31
|
+
|
32
|
+
def ==(other)
|
33
|
+
other.is_a?(Addrinfo) && (other.pid == @pid) && (other.groups == @groups)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def init_from_array(ary)
|
39
|
+
check_family(ary[0])
|
40
|
+
check_u32(ary[1])
|
41
|
+
check_u32(ary[2])
|
42
|
+
@afamily = Socket::AF_NETLINK
|
43
|
+
@pid = ary[1]
|
44
|
+
@groups = ary[2]
|
45
|
+
end
|
46
|
+
|
47
|
+
def init_from_string(str)
|
48
|
+
ary = str.unpack('SSLL')
|
49
|
+
ary.delete_at(1)
|
50
|
+
init_from_array(ary)
|
51
|
+
end
|
52
|
+
|
53
|
+
def check_family(family)
|
54
|
+
golden = case family
|
55
|
+
when String
|
56
|
+
'AF_NETLINK'
|
57
|
+
when Integer
|
58
|
+
Socket::AF_NETLINK
|
59
|
+
else
|
60
|
+
raise TypeError, "no implicit conversion of #{family.class} to Integer/String"
|
61
|
+
end
|
62
|
+
raise SocketError, "unknown address family: #{family}" unless family == golden
|
63
|
+
end
|
64
|
+
|
65
|
+
def check_u32(value)
|
66
|
+
raise TypeError, "no implicit conversion of #{value.class} to Integer" unless value.is_a?(Integer)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Netlink
|
4
|
+
class NlMsgHdr
|
5
|
+
attr_accessor :length
|
6
|
+
attr_reader :type, :flags, :seq, :pid
|
7
|
+
|
8
|
+
# Size of a nlmsgheader
|
9
|
+
SIZE = 16
|
10
|
+
# nlmsghdr pack string
|
11
|
+
PACK_STR = 'LSSLL'
|
12
|
+
|
13
|
+
# Create a +nlmsghdr+ from a pack string
|
14
|
+
# @param [String] str
|
15
|
+
# @return [NlMsgHdr]
|
16
|
+
def self.from_string(str)
|
17
|
+
ary = str.unpack(PACK_STR)
|
18
|
+
new(*ary)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param [Integer] length message length
|
22
|
+
# @param [Integer] type message type
|
23
|
+
# @param [Integer] flags message flags
|
24
|
+
# @param [Integer] seq message sequence number
|
25
|
+
# @param [Integer] pid message port id
|
26
|
+
def initialize(length, type, flags, seq, pid)
|
27
|
+
@length = length
|
28
|
+
@type = type
|
29
|
+
@flags = flags
|
30
|
+
@seq = seq
|
31
|
+
@pid = pid
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [String]
|
35
|
+
def to_s
|
36
|
+
[@length, @type, @flags, @seq, @pid].pack(PACK_STR)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Compute +length+ field from +mesg+
|
40
|
+
# @param [String] mesg
|
41
|
+
# @return [Integer]
|
42
|
+
def compute_length(mesg)
|
43
|
+
@length = SIZE + mesg.size
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class NlMsgError
|
48
|
+
attr_reader :error_code, :orig_header
|
49
|
+
|
50
|
+
def self.from_string(msg)
|
51
|
+
error_code = msg[0, 4].unpack1('L')
|
52
|
+
orig_header = NlMsgHdr.from_string(msg[4, NlMsgHdr::SIZE])
|
53
|
+
new(error_code, orig_header)
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(error_code, orig_header)
|
57
|
+
@error_code = error_code
|
58
|
+
@orig_header = orig_header
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s
|
62
|
+
[@error_code].pack('L') << @orig_header.to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
def ack?
|
66
|
+
@error_code.zero?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
require 'forwardable'
|
5
|
+
|
6
|
+
module Netlink
|
7
|
+
# Handle a netlink socket
|
8
|
+
class Socket
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
# Netlink domain socket
|
12
|
+
AF_NETLINK = 16
|
13
|
+
# Default buffer size
|
14
|
+
DEFAULT_BUFFER_SIZE = 32 * 1024
|
15
|
+
|
16
|
+
def_delegators :@socket, :bind, :close, :fileno, :getsockopt, :setsockopt
|
17
|
+
|
18
|
+
class << self
|
19
|
+
# Generate a Port Id from Process Id (on 22 bits) and a counter (on 10 bits)
|
20
|
+
# @return [Integer]
|
21
|
+
def generate_pid
|
22
|
+
@next_pid = Process.pid << 10 unless defined? @next_pid
|
23
|
+
|
24
|
+
pid = @next_pid
|
25
|
+
@next_pid += 1
|
26
|
+
pid
|
27
|
+
end
|
28
|
+
|
29
|
+
alias old_new new
|
30
|
+
|
31
|
+
def new(family)
|
32
|
+
sock = old_new(family)
|
33
|
+
if block_given?
|
34
|
+
begin
|
35
|
+
yield sock
|
36
|
+
ensure
|
37
|
+
sock.close
|
38
|
+
end
|
39
|
+
else
|
40
|
+
sock
|
41
|
+
end
|
42
|
+
end
|
43
|
+
alias open new
|
44
|
+
|
45
|
+
# Pack +pid+ and +groups+ as a {AF_NETLINK} sockaddr string.
|
46
|
+
# @param [Integer] pid
|
47
|
+
# @param [Integer] groups
|
48
|
+
def sockaddr_nl(pid, groups)
|
49
|
+
[AF_NETLINK, 0, pid, groups].pack('SSLL')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# @param [Integer] family Netlink family
|
54
|
+
def initialize(family)
|
55
|
+
@family = family
|
56
|
+
@pid = self.class.generate_pid
|
57
|
+
@socket = ::Socket.new(AF_NETLINK, ::Socket::SOCK_RAW, family)
|
58
|
+
@seqnum = 1
|
59
|
+
@default_buffer_size = DEFAULT_BUFFER_SIZE
|
60
|
+
@groups = 0
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [Array(String, Integer, Integer)] First element is the socket family name, second is the socket's pid and the third, the groups
|
64
|
+
def addr
|
65
|
+
['AF_NETLINK', @pid, @groups]
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [String]
|
69
|
+
def inspect
|
70
|
+
"#<#{self.class}:fd #{@socket.fileno}, AF_NETLINK, #{@family}, #{@pid}>"
|
71
|
+
end
|
72
|
+
|
73
|
+
# Binds a socket to its pid and to given groups
|
74
|
+
# @param [Integer] groups
|
75
|
+
# @return [0]
|
76
|
+
# @raise [Errno]
|
77
|
+
def bind(groups)
|
78
|
+
@groups = groups
|
79
|
+
sockaddr = self.class.sockaddr_nl(@pid, groups)
|
80
|
+
@socket.bind(sockaddr)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Send +mesg+ via socket
|
84
|
+
# @param [String] mesg message to send
|
85
|
+
# @param [Integer] nlm_type Message Type
|
86
|
+
# @param [Integer] nlm_flags Netlink message flags. Should be a bitwise OR of {Netlink}::NLM_F_* constants
|
87
|
+
# @param [Integer] flags +flags+ Socket flags. Should be a bitwise OR of {::Socket}::MSG_* constants
|
88
|
+
# @param [String,Addrinfo,nil] dest_sockaddr
|
89
|
+
# @return [Integer] number of bytes sent
|
90
|
+
def sendmsg(mesg, nlm_type, nlm_flags=0, flags=0, dest_sockaddr=nil)
|
91
|
+
nlmsg = create_nlmsg(mesg, nlm_type, nlm_flags)
|
92
|
+
@socket.sendmsg(nlmsg, flags, dest_sockaddr.to_s)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Receive a message
|
96
|
+
# @param [Integer] maxmesglen maximum number of bytes to receive as message
|
97
|
+
# @param [Integer] flags +flags+ should be a bitwise OR of {::Socket}::MSG_* constants
|
98
|
+
# @return [Array(String, Addrinfo, Integer, NlMsgHdr)] +[mesg, sender_addrinfo, rflags, controls]+ where:
|
99
|
+
# * +mesg+ is the message as a String or a {NlMsgError},
|
100
|
+
# * +sender_addrinfo+ is a {Addrinfo} about sender,
|
101
|
+
# + +controls+ is the ancillary data, here the header of message as a {NlMsgHdr}.
|
102
|
+
# @raise [NlmsgError]
|
103
|
+
def recvmsg(maxmesglen=nil, flags=0)
|
104
|
+
maxmesglen ||= @default_buffer_size
|
105
|
+
maxlen = maxmesglen + NlMsgHdr::SIZE
|
106
|
+
mesg, sender_ai, = @socket.recvmsg(maxlen, flags)
|
107
|
+
hdr = NlMsgHdr.from_string(mesg.slice!(0, NlMsgHdr::SIZE))
|
108
|
+
if hdr.type == NLMSG_ERROR
|
109
|
+
mesg = NlMsgError.from_string(mesg)
|
110
|
+
raise Error, "Error #{mesg.error_code} for message with seq #{mesg.orig_header.seq} from pid #{mesg.orig_header.pid}" unless mesg.ack?
|
111
|
+
end
|
112
|
+
|
113
|
+
mesg = mesg[0, maxmesglen] if mesg.is_a?(String)
|
114
|
+
[mesg, Addrinfo.new(sender_ai.to_sockaddr), hdr]
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
# Create a NlMsg from +mesg+ by adding header and padding
|
120
|
+
# @param [String] mesg
|
121
|
+
# @param [Integer] type message type
|
122
|
+
# @param [Integer] flags +flags+ should be a bitwise OR of {Netlink}::NETLINK_F_* constants
|
123
|
+
# @return [String]
|
124
|
+
def create_nlmsg(mesg, type, flags)
|
125
|
+
hdr = NlMsgHdr.new(0, type, flags, seqnum, @pid)
|
126
|
+
hdr.compute_length(mesg)
|
127
|
+
hdr.to_s << mesg
|
128
|
+
end
|
129
|
+
|
130
|
+
# Return sequence number to use
|
131
|
+
# @return [Integer]
|
132
|
+
def seqnum
|
133
|
+
current_seqnum = @seqnum
|
134
|
+
@seqnum += 1
|
135
|
+
current_seqnum
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/lib/netlink.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'netlink/version'
|
4
|
+
|
5
|
+
# Pure ruby netlink library
|
6
|
+
module Netlink
|
7
|
+
# Base class for Netlink errors
|
8
|
+
class Error < StandardError; end
|
9
|
+
# Error when using {Socket}
|
10
|
+
class SocketError < Error; end
|
11
|
+
|
12
|
+
# Routing/device hook
|
13
|
+
NETLINK_ROUTE = 0
|
14
|
+
# Reserved for user mode socket protocols
|
15
|
+
NETLINK_USERSOCK = 2
|
16
|
+
# socket monitoring
|
17
|
+
NETLINK_SOCK_DIAG = 4
|
18
|
+
NETLINK_INET_DIAG = NETLINK_SOCK_DIAG
|
19
|
+
# netfilter/iptables ULOG
|
20
|
+
NETLINK_NFLOG = 5
|
21
|
+
# ipsec
|
22
|
+
NETLINK_XFRM = 6
|
23
|
+
# SELinux event notifications
|
24
|
+
NETLINK_SELINUX = 7
|
25
|
+
# Open-iSCSI
|
26
|
+
NETLINK_ISCSI = 8
|
27
|
+
# auditing
|
28
|
+
NETLINK_AUDIT = 9
|
29
|
+
NETLINK_FIB_LOOKUP = 10
|
30
|
+
NETLINK_CONNECTOR = 11
|
31
|
+
# netfilter subsystem
|
32
|
+
NETLINK_NETFILTER = 12
|
33
|
+
NETLINK_IP6_FW = 13
|
34
|
+
# DECnet routing messages
|
35
|
+
NETLINK_DNRTMSG = 14
|
36
|
+
# Kernel messages to userspace
|
37
|
+
NETLINK_KOBJECT_UEVENT = 15
|
38
|
+
NETLINK_GENERIC = 16
|
39
|
+
# SCSI Transports
|
40
|
+
NETLINK_SCSITRANSPORT = 18
|
41
|
+
NETLINK_ECRYPTFS = 19
|
42
|
+
NETLINK_RDMA = 20
|
43
|
+
# Crypto layer
|
44
|
+
NETLINK_CRYPTO = 21
|
45
|
+
# SMC monitoring
|
46
|
+
NETLINK_SMC = 22
|
47
|
+
|
48
|
+
# Must be set on all request messages.
|
49
|
+
NLM_F_REQUEST = 0x01
|
50
|
+
# The message is part of a multipart message terminated by NLMSG_DONE.
|
51
|
+
NLM_F_MULTI = 0x02
|
52
|
+
# Request for an acknowlegement on succes.
|
53
|
+
NLM_F_ACK = 0x04
|
54
|
+
# Echo this request.
|
55
|
+
NLM_F_ECHO = 0x08
|
56
|
+
|
57
|
+
NLMSG_NOOP = 1
|
58
|
+
NLMSG_ERROR = 2
|
59
|
+
NLMSG_DONE = 3
|
60
|
+
end
|
61
|
+
|
62
|
+
require_relative 'netlink/addrinfo'
|
63
|
+
require_relative 'netlink/nlmsghdr'
|
64
|
+
require_relative 'netlink/socket'
|
data/netlink.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/netlink/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'netlink'
|
7
|
+
spec.version = Netlink::VERSION
|
8
|
+
spec.authors = ['Sylvain Daubert']
|
9
|
+
spec.email = ['sylvain.daubert@laposte.net']
|
10
|
+
|
11
|
+
spec.summary = 'Ruby library to use Netlink sockets on Linux'
|
12
|
+
spec.homepage = 'https://github.com/sdaubert/netlink'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
spec.required_ruby_version = '>= 2.7.0'
|
15
|
+
|
16
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
17
|
+
|
18
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
19
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
20
|
+
spec.metadata['changelog_uri'] = 'https://github.com/sdaubert/netlink/CHANGELOG.md'
|
21
|
+
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
25
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
26
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
# spec.bindir = "exe"
|
30
|
+
# spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
31
|
+
spec.require_paths = ['lib']
|
32
|
+
|
33
|
+
# Uncomment to register a new dependency of your gem
|
34
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
35
|
+
|
36
|
+
# For more information and examples about making a new gem, check out our
|
37
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
38
|
+
end
|
data/sig/netlink.rbs
ADDED
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: netlink
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sylvain Daubert
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-02-07 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email:
|
15
|
+
- sylvain.daubert@laposte.net
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".rspec"
|
21
|
+
- ".rubocop.yml"
|
22
|
+
- ".solargraph.yml"
|
23
|
+
- CHANGELOG.md
|
24
|
+
- Gemfile
|
25
|
+
- LICENSE.txt
|
26
|
+
- README.md
|
27
|
+
- Rakefile
|
28
|
+
- bin/console
|
29
|
+
- bin/setup
|
30
|
+
- lib/netlink.rb
|
31
|
+
- lib/netlink/addrinfo.rb
|
32
|
+
- lib/netlink/nlmsghdr.rb
|
33
|
+
- lib/netlink/socket.rb
|
34
|
+
- lib/netlink/version.rb
|
35
|
+
- netlink.gemspec
|
36
|
+
- sig/netlink.rbs
|
37
|
+
homepage: https://github.com/sdaubert/netlink
|
38
|
+
licenses:
|
39
|
+
- MIT
|
40
|
+
metadata:
|
41
|
+
allowed_push_host: https://rubygems.org
|
42
|
+
homepage_uri: https://github.com/sdaubert/netlink
|
43
|
+
source_code_uri: https://github.com/sdaubert/netlink
|
44
|
+
changelog_uri: https://github.com/sdaubert/netlink/CHANGELOG.md
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.7.0
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
requirements: []
|
60
|
+
rubygems_version: 3.2.5
|
61
|
+
signing_key:
|
62
|
+
specification_version: 4
|
63
|
+
summary: Ruby library to use Netlink sockets on Linux
|
64
|
+
test_files: []
|