github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/system/net/net_posix.go (about) 1 //go:build darwin 2 3 package net 4 5 import ( 6 "context" 7 "fmt" 8 "github.com/isyscore/isc-gobase/system/common" 9 "net" 10 "strconv" 11 "strings" 12 "syscall" 13 ) 14 15 // Connections Return a list of network connections opened. 16 func Connections(kind string) ([]ConnectionStat, error) { 17 return ConnectionsWithContext(context.Background(), kind) 18 } 19 20 func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { 21 return ConnectionsPid(kind, 0) 22 } 23 24 // ConnectionsMax Return a list of network connections opened returning at most `max` 25 // connections for each running process. 26 func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) { 27 return ConnectionsMaxWithContext(context.Background(), kind, max) 28 } 29 30 func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) { 31 return []ConnectionStat{}, common.ErrNotImplementedError 32 } 33 34 // ConnectionsPid Return a list of network connections opened by a process. 35 func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) { 36 return ConnectionsPidWithContext(context.Background(), kind, pid) 37 } 38 39 func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) { 40 var ret []ConnectionStat 41 42 args := []string{"-i"} 43 switch strings.ToLower(kind) { 44 default: 45 fallthrough 46 case "": 47 fallthrough 48 case "all": 49 fallthrough 50 case "inet": 51 args = append(args, "tcp", "-i", "udp") 52 case "inet4": 53 args = append(args, "4") 54 case "inet6": 55 args = append(args, "6") 56 case "tcp": 57 args = append(args, "tcp") 58 case "tcp4": 59 args = append(args, "4tcp") 60 case "tcp6": 61 args = append(args, "6tcp") 62 case "udp": 63 args = append(args, "udp") 64 case "udp4": 65 args = append(args, "4udp") 66 case "udp6": 67 args = append(args, "6udp") 68 case "unix": 69 args = []string{"-U"} 70 } 71 72 r, err := common.CallLsofWithContext(ctx, invoke, pid, args...) 73 if err != nil { 74 return nil, err 75 } 76 for _, rr := range r { 77 if strings.HasPrefix(rr, "COMMAND") { 78 continue 79 } 80 n, err := parseNetLine(rr) 81 if err != nil { 82 83 continue 84 } 85 86 ret = append(ret, n) 87 } 88 89 return ret, nil 90 } 91 92 var constMap = map[string]int{ 93 "unix": syscall.AF_UNIX, 94 "TCP": syscall.SOCK_STREAM, 95 "UDP": syscall.SOCK_DGRAM, 96 "IPv4": syscall.AF_INET, 97 "IPv6": syscall.AF_INET6, 98 } 99 100 func parseNetLine(line string) (ConnectionStat, error) { 101 f := strings.Fields(line) 102 if len(f) < 8 { 103 return ConnectionStat{}, fmt.Errorf("wrong line,%s", line) 104 } 105 106 if len(f) == 8 { 107 f = append(f, f[7]) 108 f[7] = "unix" 109 } 110 111 pid, err := strconv.Atoi(f[1]) 112 if err != nil { 113 return ConnectionStat{}, err 114 } 115 fd, err := strconv.Atoi(strings.Trim(f[3], "u")) 116 if err != nil { 117 return ConnectionStat{}, fmt.Errorf("unknown fd, %s", f[3]) 118 } 119 netFamily, ok := constMap[f[4]] 120 if !ok { 121 return ConnectionStat{}, fmt.Errorf("unknown family, %s", f[4]) 122 } 123 netType, ok := constMap[f[7]] 124 if !ok { 125 return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[7]) 126 } 127 128 var laddr, raddr Addr 129 if f[7] == "unix" { 130 laddr.IP = f[8] 131 } else { 132 laddr, raddr, err = parseNetAddr(f[8]) 133 if err != nil { 134 return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s", f[8]) 135 } 136 } 137 138 n := ConnectionStat{ 139 Fd: uint32(fd), 140 Family: uint32(netFamily), 141 Type: uint32(netType), 142 Laddr: laddr, 143 Raddr: raddr, 144 Pid: int32(pid), 145 } 146 if len(f) == 10 { 147 n.Status = strings.Trim(f[9], "()") 148 } 149 150 return n, nil 151 } 152 153 func parseNetAddr(line string) (laddr Addr, raddr Addr, err error) { 154 parse := func(l string) (Addr, error) { 155 host, port, err := net.SplitHostPort(l) 156 if err != nil { 157 return Addr{}, fmt.Errorf("wrong addr, %s", l) 158 } 159 lport, err := strconv.Atoi(port) 160 if err != nil { 161 return Addr{}, err 162 } 163 return Addr{IP: host, Port: uint32(lport)}, nil 164 } 165 166 addrs := strings.Split(line, "->") 167 if len(addrs) == 0 { 168 return laddr, raddr, fmt.Errorf("wrong netaddr, %s", line) 169 } 170 laddr, err = parse(addrs[0]) 171 if len(addrs) == 2 { // remote addr exists 172 raddr, err = parse(addrs[1]) 173 if err != nil { 174 return laddr, raddr, err 175 } 176 } 177 178 return laddr, raddr, err 179 } 180 181 // ConnectionsPidMax Return up to `max` network connections opened by a process. 182 func ConnectionsPidMax(kind string, pid int32, max int) ([]ConnectionStat, error) { 183 return ConnectionsPidMaxWithContext(context.Background(), kind, pid, max) 184 } 185 186 func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { 187 return []ConnectionStat{}, common.ErrNotImplementedError 188 } 189 190 // ConnectionsWithoutUids Return a list of network connections opened, omitting `Uids`. 191 // WithoutUids functions are reliant on implementation details. They may be altered to be an alias for Connections or be 192 // removed from the API in the future. 193 func ConnectionsWithoutUids(kind string) ([]ConnectionStat, error) { 194 return ConnectionsWithoutUidsWithContext(context.Background(), kind) 195 } 196 197 func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { 198 return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0) 199 } 200 201 func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) { 202 return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, max) 203 } 204 205 func ConnectionsPidWithoutUids(kind string, pid int32) ([]ConnectionStat, error) { 206 return ConnectionsPidWithoutUidsWithContext(context.Background(), kind, pid) 207 } 208 209 func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) { 210 return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0) 211 } 212 213 func ConnectionsPidMaxWithoutUids(kind string, pid int32, max int) ([]ConnectionStat, error) { 214 return ConnectionsPidMaxWithoutUidsWithContext(context.Background(), kind, pid, max) 215 } 216 217 func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { 218 return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, max) 219 } 220 221 func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { 222 return []ConnectionStat{}, common.ErrNotImplementedError 223 }