guile-netlink/ip/addr.scm

addr.scm

1
;;;; Copyright (C) 2021 Julien Lepiller <julien@lepiller.eu>
2
;;;; 
3
;;;; This library is free software; you can redistribute it and/or
4
;;;; modify it under the terms of the GNU Lesser General Public
5
;;;; License as published by the Free Software Foundation; either
6
;;;; version 3 of the License, or (at your option) any later version.
7
;;;; 
8
;;;; This library is distributed in the hope that it will be useful,
9
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
;;;; Lesser General Public License for more details.
12
;;;; 
13
;;;; You should have received a copy of the GNU Lesser General Public
14
;;;; License along with this library; if not, write to the Free Software
15
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
;;;; 
17
18
(define-module (ip addr)
19
  #:use-module (ice-9 match)
20
  #:use-module (ip link)
21
  #:use-module (ip utils)
22
  #:use-module (netlink route addr)
23
  #:use-module (netlink route attrs)
24
  #:use-module (netlink connection)
25
  #:use-module (netlink constant)
26
  #:use-module (netlink deserialize)
27
  #:use-module (netlink message)
28
  #:use-module (netlink standard)
29
  #:use-module (srfi srfi-1)
30
  #:use-module (srfi srfi-9)
31
  #:export (addr-add
32
            addr-del
33
            addr-show))
34
35
(define-record-type <addr>
36
  (make-addr family prefix flags scope link label addr brd cacheinfo)
37
  addr?
38
  (family    addr-family)
39
  (prefix    addr-prefix)
40
  (flags     addr-flags)
41
  (scope     addr-scope)
42
  (link      addr-link)
43
  (label     addr-label)
44
  (addr      addr-addr)
45
  (brd       addr-brd)
46
  (cacheinfo addr-cacheinfo))
47
48
(define (cidr->addr str)
49
  (match (string-split str #\/)
50
    ((addr) addr)
51
    ((addr prefix) addr)
52
    (_ (throw 'incorrect-cidr-notation str))))
53
54
(define (cidr->prefix str)
55
  (match (string-split str #\/)
56
    ((addr) #f)
57
    ((addr prefix) (string->number prefix))
58
    (_ (throw 'incorrect-cidr-notation str))))
59
60
(define* (addr-del device cidr #:key (ipv6? #f))
61
  (define request-num (random 65535))
62
  (define prefix (cidr->prefix cidr))
63
  (define addr (cidr->addr cidr))
64
65
  (define index
66
    (cond
67
      ((number? device) device)
68
      ((string? device) (link-name->index device))))
69
70
  (define message
71
    (make-message
72
      RTM_DELADDR
73
      (logior NLM_F_REQUEST NLM_F_ACK)
74
      request-num
75
      0
76
      (make-addr-message
77
        (if ipv6? AF_INET6 AF_INET)
78
        (if prefix prefix 0)
79
        0
80
        0
81
        index
82
        (list
83
          (make-route-attr IFA_LOCAL
84
            ((if ipv6?
85
                 make-ipv6-route-attr
86
                 make-ipv4-route-attr)
87
             addr))
88
          (make-route-attr IFA_ADDRESS
89
            ((if ipv6?
90
                 make-ipv6-route-attr
91
                 make-ipv4-route-attr)
92
             addr))))))
93
94
  (let ((sock (connect-route)))
95
    (send-msg message sock)
96
    (let ((answer (receive-and-decode-msg sock %default-route-decoder)))
97
      (close-socket sock)
98
      (answer-ok? (last answer)))))
99
100
(define* (addr-add device cidr #:key (ipv6? #f))
101
  (define request-num (random 65535))
102
  (define prefix (cidr->prefix cidr))
103
  (define addr (cidr->addr cidr))
104
105
  (define index
106
    (cond
107
      ((number? device) device)
108
      ((string? device) (link-name->index device))))
109
110
  (define message
111
    (make-message
112
      RTM_NEWADDR
113
      (logior NLM_F_REQUEST NLM_F_ACK NLM_F_EXCL NLM_F_CREATE)
114
      request-num
115
      0
116
      (make-addr-message
117
        (if ipv6? AF_INET6 AF_INET)
118
        (if prefix prefix 0)
119
        0
120
        0
121
        index
122
        (list
123
          (make-route-attr IFA_LOCAL
124
            ((if ipv6?
125
                 make-ipv6-route-attr
126
                 make-ipv4-route-attr)
127
             addr))
128
          (make-route-attr IFA_ADDRESS
129
            ((if ipv6?
130
                 make-ipv6-route-attr
131
                 make-ipv4-route-attr)
132
             addr))))))
133
134
  (let ((sock (connect-route)))
135
    (send-msg message sock)
136
    (let ((answer (receive-and-decode-msg sock %default-route-decoder)))
137
      (close-socket sock)
138
      (answer-ok? (last answer)))))
139
140
(define (get-addrs)
141
  (define request-num (random 65535))
142
  (define message
143
    (make-message
144
      RTM_GETADDR
145
      (logior NLM_F_REQUEST NLM_F_DUMP)
146
      request-num
147
      0
148
      (make-addr-message AF_UNSPEC 0 0 0 0 '())))
149
  (let ((sock (connect-route)))
150
    (send-msg message sock)
151
    (let* ((answer (receive-and-decode-msg sock %default-route-decoder))
152
           (addrs (filter
153
                    (lambda (msg) (equal? (message-kind msg) RTM_NEWADDR))
154
                    answer))
155
           (addrs (map
156
                    (lambda (msg)
157
                      (let* ((data (message-data msg))
158
                             (attrs (addr-message-attrs data)))
159
                        (make-addr
160
                          (addr-message-family data)
161
                          (addr-message-prefix-len data)
162
                          (map
163
                            int->ifa-flag
164
                            (split-flags (logior (addr-message-flags data)
165
                                                 (get-attr attrs IFA_FLAGS))))
166
                          (addr-message-scope data)
167
                          (addr-message-index data)
168
                          (get-attr attrs IFA_LABEL)
169
                          (get-attr attrs IFA_ADDRESS)
170
                          (get-attr attrs IFA_BROADCAST)
171
                          (get-attr attrs IFA_CACHEINFO))))
172
                    addrs)))
173
      (close-socket sock)
174
      addrs)))
175
176
(define print-addr
177
  (match-lambda
178
    (($ <addr> family prefix flags scope link label addr brd cacheinfo)
179
     (format #t "    ~a ~a"
180
             (match family (AF_INET "inet") (AF_INET6 "inet6"))
181
             addr)
182
     (when brd
183
       (format #t " brd ~a" brd))
184
     (when scope
185
       (format #t " scope ~a"
186
               (match scope
187
                 (RT_SCOPE_UNIVERSE "global")
188
                 (_ (substring (symbol->string (int->rtm-scope scope)) 8)))))
189
190
     (for-each
191
       (lambda (flag)
192
         (unless (equal? flag 'IFA_F_PERMANENT)
193
           (format #t " ~a"
194
                   (substring (symbol->string flag) 6))))
195
       flags)
196
197
     (when label
198
       (format #t " ~a" label))
199
200
     (format #t "~%")
201
     (when cacheinfo
202
       (if (member 'IFA_F_PERMANENT flags)
203
           (format #t "        valid_lft forever preferred_lft forever~%")
204
           (format #t "        valid_lft ~asec preferred_lft ~asec~%"
205
                   (route-cache-info-attr-type-valid cacheinfo)
206
                   (route-cache-info-attr-type-prefered cacheinfo)))))))
207
208
209
(define* (addr-show #:optional (device #f))
210
  (define links (get-links))
211
  (define index
212
    (cond
213
      ((number? device) device)
214
      ((string? device) (link-name->index device))
215
      (else #f)))
216
  (define addrs (get-addrs))
217
218
  (for-each
219
    (lambda (link)
220
      (unless (and index (not (equal? (link-id link) index)))
221
        (print-link link)
222
        (for-each print-addr
223
                  (filter (lambda (addr) (equal? (link-id link) (addr-link addr)))
224
                          addrs))))
225
    links))
226