github.com/sagernet/netlink@v0.0.0-20240612041022-b9a21c07ac6a/gtp_linux.go (about) 1 package netlink 2 3 import ( 4 "fmt" 5 "net" 6 "strings" 7 "syscall" 8 9 "github.com/sagernet/netlink/nl" 10 "golang.org/x/sys/unix" 11 ) 12 13 type PDP struct { 14 Version uint32 15 TID uint64 16 PeerAddress net.IP 17 MSAddress net.IP 18 Flow uint16 19 NetNSFD uint32 20 ITEI uint32 21 OTEI uint32 22 } 23 24 func (pdp *PDP) String() string { 25 elems := []string{} 26 elems = append(elems, fmt.Sprintf("Version: %d", pdp.Version)) 27 if pdp.Version == 0 { 28 elems = append(elems, fmt.Sprintf("TID: %d", pdp.TID)) 29 } else if pdp.Version == 1 { 30 elems = append(elems, fmt.Sprintf("TEI: %d/%d", pdp.ITEI, pdp.OTEI)) 31 } 32 elems = append(elems, fmt.Sprintf("MS-Address: %s", pdp.MSAddress)) 33 elems = append(elems, fmt.Sprintf("Peer-Address: %s", pdp.PeerAddress)) 34 return fmt.Sprintf("{%s}", strings.Join(elems, " ")) 35 } 36 37 func (p *PDP) parseAttributes(attrs []syscall.NetlinkRouteAttr) error { 38 for _, a := range attrs { 39 switch a.Attr.Type { 40 case nl.GENL_GTP_ATTR_VERSION: 41 p.Version = native.Uint32(a.Value) 42 case nl.GENL_GTP_ATTR_TID: 43 p.TID = native.Uint64(a.Value) 44 case nl.GENL_GTP_ATTR_PEER_ADDRESS: 45 p.PeerAddress = net.IP(a.Value) 46 case nl.GENL_GTP_ATTR_MS_ADDRESS: 47 p.MSAddress = net.IP(a.Value) 48 case nl.GENL_GTP_ATTR_FLOW: 49 p.Flow = native.Uint16(a.Value) 50 case nl.GENL_GTP_ATTR_NET_NS_FD: 51 p.NetNSFD = native.Uint32(a.Value) 52 case nl.GENL_GTP_ATTR_I_TEI: 53 p.ITEI = native.Uint32(a.Value) 54 case nl.GENL_GTP_ATTR_O_TEI: 55 p.OTEI = native.Uint32(a.Value) 56 } 57 } 58 return nil 59 } 60 61 func parsePDP(msgs [][]byte) ([]*PDP, error) { 62 pdps := make([]*PDP, 0, len(msgs)) 63 for _, m := range msgs { 64 attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:]) 65 if err != nil { 66 return nil, err 67 } 68 pdp := &PDP{} 69 if err := pdp.parseAttributes(attrs); err != nil { 70 return nil, err 71 } 72 pdps = append(pdps, pdp) 73 } 74 return pdps, nil 75 } 76 77 func (h *Handle) GTPPDPList() ([]*PDP, error) { 78 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 79 if err != nil { 80 return nil, err 81 } 82 msg := &nl.Genlmsg{ 83 Command: nl.GENL_GTP_CMD_GETPDP, 84 Version: nl.GENL_GTP_VERSION, 85 } 86 req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_DUMP) 87 req.AddData(msg) 88 msgs, err := req.Execute(unix.NETLINK_GENERIC, 0) 89 if err != nil { 90 return nil, err 91 } 92 return parsePDP(msgs) 93 } 94 95 func GTPPDPList() ([]*PDP, error) { 96 return pkgHandle.GTPPDPList() 97 } 98 99 func gtpPDPGet(req *nl.NetlinkRequest) (*PDP, error) { 100 msgs, err := req.Execute(unix.NETLINK_GENERIC, 0) 101 if err != nil { 102 return nil, err 103 } 104 pdps, err := parsePDP(msgs) 105 if err != nil { 106 return nil, err 107 } 108 if len(pdps) != 1 { 109 return nil, fmt.Errorf("invalid reqponse for GENL_GTP_CMD_GETPDP") 110 } 111 return pdps[0], nil 112 } 113 114 func (h *Handle) GTPPDPByTID(link Link, tid int) (*PDP, error) { 115 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 116 if err != nil { 117 return nil, err 118 } 119 msg := &nl.Genlmsg{ 120 Command: nl.GENL_GTP_CMD_GETPDP, 121 Version: nl.GENL_GTP_VERSION, 122 } 123 req := h.newNetlinkRequest(int(f.ID), 0) 124 req.AddData(msg) 125 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(0))) 126 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) 127 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(uint64(tid)))) 128 return gtpPDPGet(req) 129 } 130 131 func GTPPDPByTID(link Link, tid int) (*PDP, error) { 132 return pkgHandle.GTPPDPByTID(link, tid) 133 } 134 135 func (h *Handle) GTPPDPByITEI(link Link, itei int) (*PDP, error) { 136 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 137 if err != nil { 138 return nil, err 139 } 140 msg := &nl.Genlmsg{ 141 Command: nl.GENL_GTP_CMD_GETPDP, 142 Version: nl.GENL_GTP_VERSION, 143 } 144 req := h.newNetlinkRequest(int(f.ID), 0) 145 req.AddData(msg) 146 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(1))) 147 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) 148 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(uint32(itei)))) 149 return gtpPDPGet(req) 150 } 151 152 func GTPPDPByITEI(link Link, itei int) (*PDP, error) { 153 return pkgHandle.GTPPDPByITEI(link, itei) 154 } 155 156 func (h *Handle) GTPPDPByMSAddress(link Link, addr net.IP) (*PDP, error) { 157 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 158 if err != nil { 159 return nil, err 160 } 161 msg := &nl.Genlmsg{ 162 Command: nl.GENL_GTP_CMD_GETPDP, 163 Version: nl.GENL_GTP_VERSION, 164 } 165 req := h.newNetlinkRequest(int(f.ID), 0) 166 req.AddData(msg) 167 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(0))) 168 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) 169 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_MS_ADDRESS, []byte(addr.To4()))) 170 return gtpPDPGet(req) 171 } 172 173 func GTPPDPByMSAddress(link Link, addr net.IP) (*PDP, error) { 174 return pkgHandle.GTPPDPByMSAddress(link, addr) 175 } 176 177 func (h *Handle) GTPPDPAdd(link Link, pdp *PDP) error { 178 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 179 if err != nil { 180 return err 181 } 182 msg := &nl.Genlmsg{ 183 Command: nl.GENL_GTP_CMD_NEWPDP, 184 Version: nl.GENL_GTP_VERSION, 185 } 186 req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_EXCL|unix.NLM_F_ACK) 187 req.AddData(msg) 188 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version))) 189 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) 190 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_PEER_ADDRESS, []byte(pdp.PeerAddress.To4()))) 191 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_MS_ADDRESS, []byte(pdp.MSAddress.To4()))) 192 193 switch pdp.Version { 194 case 0: 195 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(pdp.TID))) 196 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_FLOW, nl.Uint16Attr(pdp.Flow))) 197 case 1: 198 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(pdp.ITEI))) 199 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_O_TEI, nl.Uint32Attr(pdp.OTEI))) 200 default: 201 return fmt.Errorf("unsupported GTP version: %d", pdp.Version) 202 } 203 _, err = req.Execute(unix.NETLINK_GENERIC, 0) 204 return err 205 } 206 207 func GTPPDPAdd(link Link, pdp *PDP) error { 208 return pkgHandle.GTPPDPAdd(link, pdp) 209 } 210 211 func (h *Handle) GTPPDPDel(link Link, pdp *PDP) error { 212 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 213 if err != nil { 214 return err 215 } 216 msg := &nl.Genlmsg{ 217 Command: nl.GENL_GTP_CMD_DELPDP, 218 Version: nl.GENL_GTP_VERSION, 219 } 220 req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_EXCL|unix.NLM_F_ACK) 221 req.AddData(msg) 222 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version))) 223 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) 224 225 switch pdp.Version { 226 case 0: 227 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(pdp.TID))) 228 case 1: 229 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(pdp.ITEI))) 230 default: 231 return fmt.Errorf("unsupported GTP version: %d", pdp.Version) 232 } 233 _, err = req.Execute(unix.NETLINK_GENERIC, 0) 234 return err 235 } 236 237 func GTPPDPDel(link Link, pdp *PDP) error { 238 return pkgHandle.GTPPDPDel(link, pdp) 239 }