@@ -11,9 +11,11 @@ import (
11
11
)
12
12
13
13
const (
14
- sizeofSocketID = 0x30
15
- sizeofSocketRequest = sizeofSocketID + 0x8
16
- sizeofSocket = sizeofSocketID + 0x18
14
+ sizeofSocketID = 0x30
15
+ sizeofSocketRequest = sizeofSocketID + 0x8
16
+ sizeofSocket = sizeofSocketID + 0x18
17
+ sizeofUnixSocketRequest = 0x18 // 24 byte
18
+ sizeofUnixSocket = 0x10 // 16 byte
17
19
)
18
20
19
21
type socketRequest struct {
@@ -67,6 +69,32 @@ func (r *socketRequest) Serialize() []byte {
67
69
68
70
func (r * socketRequest ) Len () int { return sizeofSocketRequest }
69
71
72
+ // According to linux/include/uapi/linux/unix_diag.h
73
+ type unixSocketRequest struct {
74
+ Family uint8
75
+ Protocol uint8
76
+ pad uint16
77
+ States uint32
78
+ INode uint32
79
+ Show uint32
80
+ Cookie [2 ]uint32
81
+ }
82
+
83
+ func (r * unixSocketRequest ) Serialize () []byte {
84
+ b := writeBuffer {Bytes : make ([]byte , sizeofUnixSocketRequest )}
85
+ b .Write (r .Family )
86
+ b .Write (r .Protocol )
87
+ native .PutUint16 (b .Next (2 ), r .pad )
88
+ native .PutUint32 (b .Next (4 ), r .States )
89
+ native .PutUint32 (b .Next (4 ), r .INode )
90
+ native .PutUint32 (b .Next (4 ), r .Show )
91
+ native .PutUint32 (b .Next (4 ), r .Cookie [0 ])
92
+ native .PutUint32 (b .Next (4 ), r .Cookie [1 ])
93
+ return b .Bytes
94
+ }
95
+
96
+ func (r * unixSocketRequest ) Len () int { return sizeofUnixSocketRequest }
97
+
70
98
type readBuffer struct {
71
99
Bytes []byte
72
100
pos int
@@ -115,6 +143,21 @@ func (s *Socket) deserialize(b []byte) error {
115
143
return nil
116
144
}
117
145
146
+ func (u * UnixSocket ) deserialize (b []byte ) error {
147
+ if len (b ) < sizeofUnixSocket {
148
+ return fmt .Errorf ("unix diag data short read (%d); want %d" , len (b ), sizeofUnixSocket )
149
+ }
150
+ rb := readBuffer {Bytes : b }
151
+ u .Type = rb .Read ()
152
+ u .Family = rb .Read ()
153
+ u .State = rb .Read ()
154
+ u .pad = rb .Read ()
155
+ u .INode = native .Uint32 (rb .Next (4 ))
156
+ u .Cookie [0 ] = native .Uint32 (rb .Next (4 ))
157
+ u .Cookie [1 ] = native .Uint32 (rb .Next (4 ))
158
+ return nil
159
+ }
160
+
118
161
// SocketGet returns the Socket identified by its local and remote addresses.
119
162
func SocketGet (local , remote net.Addr ) (* Socket , error ) {
120
163
localTCP , ok := local .(* net.TCPAddr )
@@ -157,7 +200,7 @@ func SocketGet(local, remote net.Addr) (*Socket, error) {
157
200
return nil , err
158
201
}
159
202
if from .Pid != nl .PidKernel {
160
- return nil , fmt .Errorf ("Wrong sender portid %d, expected %d" , from .Pid , nl .PidKernel )
203
+ return nil , fmt .Errorf ("wrong sender portid %d, expected %d" , from .Pid , nl .PidKernel )
161
204
}
162
205
if len (msgs ) == 0 {
163
206
return nil , errors .New ("no message nor error from netlink" )
@@ -305,6 +348,78 @@ func SocketDiagUDP(family uint8) ([]*Socket, error) {
305
348
return result , nil
306
349
}
307
350
351
+ // UnixSocketDiagInfo requests UNIX_DIAG_INFO for unix sockets and return with extension info.
352
+ func UnixSocketDiagInfo () ([]* UnixDiagInfoResp , error ) {
353
+ // Construct the request
354
+ var extensions uint8
355
+ extensions = 1 << UNIX_DIAG_NAME
356
+ extensions |= 1 << UNIX_DIAG_PEER
357
+ extensions |= 1 << UNIX_DIAG_RQLEN
358
+ req := nl .NewNetlinkRequest (nl .SOCK_DIAG_BY_FAMILY , unix .NLM_F_DUMP )
359
+ req .AddData (& unixSocketRequest {
360
+ Family : unix .AF_UNIX ,
361
+ States : ^ uint32 (0 ), // all states
362
+ Show : uint32 (extensions ),
363
+ })
364
+
365
+ var result []* UnixDiagInfoResp
366
+ err := socketDiagExecutor (req , func (m syscall.NetlinkMessage ) error {
367
+ sockInfo := & UnixSocket {}
368
+ if err := sockInfo .deserialize (m .Data ); err != nil {
369
+ return err
370
+ }
371
+
372
+ // Diagnosis also delivers sockets with AF_INET family, filter those
373
+ if sockInfo .Family != unix .AF_UNIX {
374
+ return nil
375
+ }
376
+
377
+ attrs , err := nl .ParseRouteAttr (m .Data [sizeofUnixSocket :])
378
+ if err != nil {
379
+ return err
380
+ }
381
+
382
+ res , err := attrsToUnixDiagInfoResp (attrs , sockInfo )
383
+ if err != nil {
384
+ return err
385
+ }
386
+ result = append (result , res )
387
+ return nil
388
+ })
389
+ if err != nil {
390
+ return nil , err
391
+ }
392
+ return result , nil
393
+ }
394
+
395
+ // UnixSocketDiag requests UNIX_DIAG_INFO for unix sockets.
396
+ func UnixSocketDiag () ([]* UnixSocket , error ) {
397
+ // Construct the request
398
+ req := nl .NewNetlinkRequest (nl .SOCK_DIAG_BY_FAMILY , unix .NLM_F_DUMP )
399
+ req .AddData (& unixSocketRequest {
400
+ Family : unix .AF_UNIX ,
401
+ States : ^ uint32 (0 ), // all states
402
+ })
403
+
404
+ var result []* UnixSocket
405
+ err := socketDiagExecutor (req , func (m syscall.NetlinkMessage ) error {
406
+ sockInfo := & UnixSocket {}
407
+ if err := sockInfo .deserialize (m .Data ); err != nil {
408
+ return err
409
+ }
410
+
411
+ // Diagnosis also delivers sockets with AF_INET family, filter those
412
+ if sockInfo .Family == unix .AF_UNIX {
413
+ result = append (result , sockInfo )
414
+ }
415
+ return nil
416
+ })
417
+ if err != nil {
418
+ return nil , err
419
+ }
420
+ return result , nil
421
+ }
422
+
308
423
// socketDiagExecutor requests diagnoses info from the NETLINK_INET_DIAG socket for the specified request.
309
424
func socketDiagExecutor (req * nl.NetlinkRequest , receiver func (syscall.NetlinkMessage ) error ) error {
310
425
s , err := nl .Subscribe (unix .NETLINK_INET_DIAG )
@@ -381,3 +496,28 @@ func attrsToInetDiagUDPInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *Sock
381
496
382
497
return info , nil
383
498
}
499
+
500
+ func attrsToUnixDiagInfoResp (attrs []syscall.NetlinkRouteAttr , sockInfo * UnixSocket ) (* UnixDiagInfoResp , error ) {
501
+ info := & UnixDiagInfoResp {
502
+ DiagMsg : sockInfo ,
503
+ }
504
+ for _ , a := range attrs {
505
+ switch a .Attr .Type {
506
+ case UNIX_DIAG_NAME :
507
+ name := string (a .Value [:a .Attr .Len ])
508
+ info .Name = & name
509
+ case UNIX_DIAG_PEER :
510
+ peer := native .Uint32 (a .Value )
511
+ info .Peer = & peer
512
+ case UNIX_DIAG_RQLEN :
513
+ info .Queue = & QueueInfo {
514
+ RQueue : native .Uint32 (a .Value [:4 ]),
515
+ WQueue : native .Uint32 (a .Value [4 :]),
516
+ }
517
+ // default:
518
+ // fmt.Println("unknown unix attribute type", a.Attr.Type, "with data", a.Value)
519
+ }
520
+ }
521
+
522
+ return info , nil
523
+ }
0 commit comments