github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/parameters/bpf.go (about) 1 /* 2 * Copyright (c) 2020, Psiphon Inc. 3 * All rights reserved. 4 * 5 * This program 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 program 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 program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package parameters 21 22 import ( 23 "encoding/json" 24 25 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors" 26 "golang.org/x/net/bpf" 27 ) 28 29 // BPFProgramSpec specifies a BPF program. The Name field is informational and 30 // may be used for logging. The Instructions field is a list of values which 31 // map to golang.org/x/net/bpf.Instruction and which can be marshaled. 32 type BPFProgramSpec struct { 33 Name string 34 Instructions []BPFInstructionSpec 35 } 36 37 // Validate validates a BPF program spec. 38 func (s *BPFProgramSpec) Validate() error { 39 if s.Name == "" { 40 return errors.TraceNew("missing name") 41 } 42 if len(s.Instructions) < 1 { 43 return errors.TraceNew("missing instructions") 44 } 45 _, err := s.Assemble() 46 return errors.Trace(err) 47 } 48 49 // Assemble converts the Instructions to equivilent 50 // golang.org/x/net/bpf.Instruction values and assembles these into raw 51 // instructions suitable for attaching to a socket. 52 func (s *BPFProgramSpec) Assemble() ([]bpf.RawInstruction, error) { 53 54 if len(s.Instructions) == 0 { 55 return nil, errors.TraceNew("empty program") 56 } 57 58 program := make([]bpf.Instruction, len(s.Instructions)) 59 for i, instructionSpec := range s.Instructions { 60 instruction, err := instructionSpec.GetInstruction() 61 if err != nil { 62 return nil, errors.Trace(err) 63 } 64 program[i] = instruction 65 } 66 67 raw, err := bpf.Assemble(program) 68 if err != nil { 69 return nil, errors.Trace(err) 70 } 71 72 return raw, nil 73 } 74 75 // BPFInstructionSpec represents a golang.org/x/net/bpf.Instruction and can be 76 // marshaled. 77 type BPFInstructionSpec struct { 78 Op string 79 Args json.RawMessage 80 } 81 82 // GetInstruction coverts a BPFInstructionSpec to the equivilent 83 // golang.org/x/net/bpf.Instruction. 84 func (s *BPFInstructionSpec) GetInstruction() (bpf.Instruction, error) { 85 switch s.Op { 86 case "ALUOpConstant": 87 var instruction bpf.ALUOpConstant 88 err := json.Unmarshal(s.Args, &instruction) 89 if err != nil { 90 return nil, errors.Trace(err) 91 } 92 return instruction, nil 93 case "ALUOpX": 94 var instruction bpf.ALUOpX 95 err := json.Unmarshal(s.Args, &instruction) 96 if err != nil { 97 return nil, errors.Trace(err) 98 } 99 return instruction, nil 100 case "Jump": 101 var instruction bpf.Jump 102 err := json.Unmarshal(s.Args, &instruction) 103 if err != nil { 104 return nil, errors.Trace(err) 105 } 106 return instruction, nil 107 case "JumpIf": 108 var instruction bpf.JumpIf 109 err := json.Unmarshal(s.Args, &instruction) 110 if err != nil { 111 return nil, errors.Trace(err) 112 } 113 return instruction, nil 114 case "JumpIfX": 115 var instruction bpf.JumpIfX 116 err := json.Unmarshal(s.Args, &instruction) 117 if err != nil { 118 return nil, errors.Trace(err) 119 } 120 return instruction, nil 121 case "LoadAbsolute": 122 var instruction bpf.LoadAbsolute 123 err := json.Unmarshal(s.Args, &instruction) 124 if err != nil { 125 return nil, errors.Trace(err) 126 } 127 return instruction, nil 128 case "LoadConstant": 129 var instruction bpf.LoadConstant 130 err := json.Unmarshal(s.Args, &instruction) 131 if err != nil { 132 return nil, errors.Trace(err) 133 } 134 return instruction, nil 135 case "LoadExtension": 136 var instruction bpf.LoadExtension 137 err := json.Unmarshal(s.Args, &instruction) 138 if err != nil { 139 return nil, errors.Trace(err) 140 } 141 return instruction, nil 142 case "LoadIndirect": 143 var instruction bpf.LoadIndirect 144 err := json.Unmarshal(s.Args, &instruction) 145 if err != nil { 146 return nil, errors.Trace(err) 147 } 148 return instruction, nil 149 case "LoadMemShift": 150 var instruction bpf.LoadMemShift 151 err := json.Unmarshal(s.Args, &instruction) 152 if err != nil { 153 return nil, errors.Trace(err) 154 } 155 return instruction, nil 156 case "LoadScratch": 157 var instruction bpf.LoadScratch 158 err := json.Unmarshal(s.Args, &instruction) 159 if err != nil { 160 return nil, errors.Trace(err) 161 } 162 return instruction, nil 163 case "NegateA": 164 var instruction bpf.NegateA 165 err := json.Unmarshal(s.Args, &instruction) 166 if err != nil { 167 return nil, errors.Trace(err) 168 } 169 return instruction, nil 170 case "RetA": 171 var instruction bpf.RetA 172 err := json.Unmarshal(s.Args, &instruction) 173 if err != nil { 174 return nil, errors.Trace(err) 175 } 176 return instruction, nil 177 case "RetConstant": 178 var instruction bpf.RetConstant 179 err := json.Unmarshal(s.Args, &instruction) 180 if err != nil { 181 return nil, errors.Trace(err) 182 } 183 return instruction, nil 184 case "StoreScratch": 185 var instruction bpf.StoreScratch 186 err := json.Unmarshal(s.Args, &instruction) 187 if err != nil { 188 return nil, errors.Trace(err) 189 } 190 return instruction, nil 191 case "TAX": 192 var instruction bpf.TAX 193 err := json.Unmarshal(s.Args, &instruction) 194 if err != nil { 195 return nil, errors.Trace(err) 196 } 197 return instruction, nil 198 case "TXA": 199 var instruction bpf.TXA 200 err := json.Unmarshal(s.Args, &instruction) 201 if err != nil { 202 return nil, errors.Trace(err) 203 } 204 return instruction, nil 205 } 206 207 return nil, errors.Tracef("unknown bpf instruction: %s", s.Op) 208 }