guile-netlink/ip/addr.scm

addr.scm

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