├── .gitignore ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── LICENSE ├── Makefile ├── README.md ├── audit_constant.go ├── audit_events.go ├── auditconstant_string.go ├── auditprint └── auditprint.go ├── buffer.go ├── headers ├── access_tab.go ├── audit_x64.go ├── audit_x64_i2s.go ├── cap_tab.go ├── clock_tab.go ├── cloneflag_tab.go ├── epollctl_tab.go ├── fcntl_cmd_tab.go ├── field_tab.go ├── ftype_tab.go ├── icmptype_tab.go ├── ioctlreq_tab.go ├── ip6optname_tab.go ├── ipc_tab.go ├── ipoptname_tab.go ├── mmap_tab.go ├── mount_tab.go ├── nfproto_tab.go ├── pktoptname_tab.go ├── prctl_opt_tab.go ├── protocol_tab.go ├── ptrace_tab.go ├── recv_tab.go ├── rlimit_tab.go ├── sched_tab.go ├── seccomp_tab.go ├── seek_tab.go ├── signal_tab.go ├── sock_tab.go ├── sockfam_tab.go ├── socklevel_tab.go ├── sockoptname_tab.go ├── socktype_tab.go ├── tcpoptname_tab.go └── umount_tab.go ├── interpret.go ├── libaudit.go ├── libaudit_test.go ├── lookup_tables.go ├── parser.go ├── parser_test.go ├── rules.go ├── rules_test.go ├── s2i_type_conversion.json ├── testdata ├── badpathnostrictpath.json ├── rules.json └── strictpathfail.json └── vendor └── github.com └── lunixbochs └── struc ├── .travis.yml ├── LICENSE ├── README.md ├── bench_test.go ├── binary.go ├── custom.go ├── custom_float16.go ├── custom_float16_test.go ├── custom_test.go ├── field.go ├── field_test.go ├── fields.go ├── fields_test.go ├── legacy.go ├── packable_test.go ├── packer.go ├── parse.go ├── parse_test.go ├── struc.go ├── struc_test.go ├── types.go └── types_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | dist: trusty 3 | sudo: required 4 | notifications: 5 | email: false 6 | go: 7 | - 1.8 8 | before_install: 9 | - sudo apt-get -qq update 10 | - sudo apt-get install -y auditd 11 | script: 12 | - sudo service auditd stop 13 | - make test 14 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Participation Guidelines 2 | 3 | This repository is governed by Mozilla's code of conduct and etiquette guidelines. 4 | For more details, please read the 5 | [Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/). 6 | 7 | ## How to Report 8 | For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page. 9 | 10 | 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License, version 2.0 2 | 3 | 1. Definitions 4 | 5 | 1.1. "Contributor" 6 | 7 | means each individual or legal entity that creates, contributes to the 8 | creation of, or owns Covered Software. 9 | 10 | 1.2. "Contributor Version" 11 | 12 | means the combination of the Contributions of others (if any) used by a 13 | Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | 17 | means Covered Software of a particular Contributor. 18 | 19 | 1.4. "Covered Software" 20 | 21 | means Source Code Form to which the initial Contributor has attached the 22 | notice in Exhibit A, the Executable Form of such Source Code Form, and 23 | Modifications of such Source Code Form, in each case including portions 24 | thereof. 25 | 26 | 1.5. "Incompatible With Secondary Licenses" 27 | means 28 | 29 | a. that the initial Contributor has attached the notice described in 30 | Exhibit B to the Covered Software; or 31 | 32 | b. that the Covered Software was made available under the terms of 33 | version 1.1 or earlier of the License, but not also under the terms of 34 | a Secondary License. 35 | 36 | 1.6. "Executable Form" 37 | 38 | means any form of the work other than Source Code Form. 39 | 40 | 1.7. "Larger Work" 41 | 42 | means a work that combines Covered Software with other material, in a 43 | separate file or files, that is not Covered Software. 44 | 45 | 1.8. "License" 46 | 47 | means this document. 48 | 49 | 1.9. "Licensable" 50 | 51 | means having the right to grant, to the maximum extent possible, whether 52 | at the time of the initial grant or subsequently, any and all of the 53 | rights conveyed by this License. 54 | 55 | 1.10. "Modifications" 56 | 57 | means any of the following: 58 | 59 | a. any file in Source Code Form that results from an addition to, 60 | deletion from, or modification of the contents of Covered Software; or 61 | 62 | b. any new file in Source Code Form that contains any Covered Software. 63 | 64 | 1.11. "Patent Claims" of a Contributor 65 | 66 | means any patent claim(s), including without limitation, method, 67 | process, and apparatus claims, in any patent Licensable by such 68 | Contributor that would be infringed, but for the grant of the License, 69 | by the making, using, selling, offering for sale, having made, import, 70 | or transfer of either its Contributions or its Contributor Version. 71 | 72 | 1.12. "Secondary License" 73 | 74 | means either the GNU General Public License, Version 2.0, the GNU Lesser 75 | General Public License, Version 2.1, the GNU Affero General Public 76 | License, Version 3.0, or any later versions of those licenses. 77 | 78 | 1.13. "Source Code Form" 79 | 80 | means the form of the work preferred for making modifications. 81 | 82 | 1.14. "You" (or "Your") 83 | 84 | means an individual or a legal entity exercising rights under this 85 | License. For legal entities, "You" includes any entity that controls, is 86 | controlled by, or is under common control with You. For purposes of this 87 | definition, "control" means (a) the power, direct or indirect, to cause 88 | the direction or management of such entity, whether by contract or 89 | otherwise, or (b) ownership of more than fifty percent (50%) of the 90 | outstanding shares or beneficial ownership of such entity. 91 | 92 | 93 | 2. License Grants and Conditions 94 | 95 | 2.1. Grants 96 | 97 | Each Contributor hereby grants You a world-wide, royalty-free, 98 | non-exclusive license: 99 | 100 | a. under intellectual property rights (other than patent or trademark) 101 | Licensable by such Contributor to use, reproduce, make available, 102 | modify, display, perform, distribute, and otherwise exploit its 103 | Contributions, either on an unmodified basis, with Modifications, or 104 | as part of a Larger Work; and 105 | 106 | b. under Patent Claims of such Contributor to make, use, sell, offer for 107 | sale, have made, import, and otherwise transfer either its 108 | Contributions or its Contributor Version. 109 | 110 | 2.2. Effective Date 111 | 112 | The licenses granted in Section 2.1 with respect to any Contribution 113 | become effective for each Contribution on the date the Contributor first 114 | distributes such Contribution. 115 | 116 | 2.3. Limitations on Grant Scope 117 | 118 | The licenses granted in this Section 2 are the only rights granted under 119 | this License. No additional rights or licenses will be implied from the 120 | distribution or licensing of Covered Software under this License. 121 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 122 | Contributor: 123 | 124 | a. for any code that a Contributor has removed from Covered Software; or 125 | 126 | b. for infringements caused by: (i) Your and any other third party's 127 | modifications of Covered Software, or (ii) the combination of its 128 | Contributions with other software (except as part of its Contributor 129 | Version); or 130 | 131 | c. under Patent Claims infringed by Covered Software in the absence of 132 | its Contributions. 133 | 134 | This License does not grant any rights in the trademarks, service marks, 135 | or logos of any Contributor (except as may be necessary to comply with 136 | the notice requirements in Section 3.4). 137 | 138 | 2.4. Subsequent Licenses 139 | 140 | No Contributor makes additional grants as a result of Your choice to 141 | distribute the Covered Software under a subsequent version of this 142 | License (see Section 10.2) or under the terms of a Secondary License (if 143 | permitted under the terms of Section 3.3). 144 | 145 | 2.5. Representation 146 | 147 | Each Contributor represents that the Contributor believes its 148 | Contributions are its original creation(s) or it has sufficient rights to 149 | grant the rights to its Contributions conveyed by this License. 150 | 151 | 2.6. Fair Use 152 | 153 | This License is not intended to limit any rights You have under 154 | applicable copyright doctrines of fair use, fair dealing, or other 155 | equivalents. 156 | 157 | 2.7. Conditions 158 | 159 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in 160 | Section 2.1. 161 | 162 | 163 | 3. Responsibilities 164 | 165 | 3.1. Distribution of Source Form 166 | 167 | All distribution of Covered Software in Source Code Form, including any 168 | Modifications that You create or to which You contribute, must be under 169 | the terms of this License. You must inform recipients that the Source 170 | Code Form of the Covered Software is governed by the terms of this 171 | License, and how they can obtain a copy of this License. You may not 172 | attempt to alter or restrict the recipients' rights in the Source Code 173 | Form. 174 | 175 | 3.2. Distribution of Executable Form 176 | 177 | If You distribute Covered Software in Executable Form then: 178 | 179 | a. such Covered Software must also be made available in Source Code Form, 180 | as described in Section 3.1, and You must inform recipients of the 181 | Executable Form how they can obtain a copy of such Source Code Form by 182 | reasonable means in a timely manner, at a charge no more than the cost 183 | of distribution to the recipient; and 184 | 185 | b. You may distribute such Executable Form under the terms of this 186 | License, or sublicense it under different terms, provided that the 187 | license for the Executable Form does not attempt to limit or alter the 188 | recipients' rights in the Source Code Form under this License. 189 | 190 | 3.3. Distribution of a Larger Work 191 | 192 | You may create and distribute a Larger Work under terms of Your choice, 193 | provided that You also comply with the requirements of this License for 194 | the Covered Software. If the Larger Work is a combination of Covered 195 | Software with a work governed by one or more Secondary Licenses, and the 196 | Covered Software is not Incompatible With Secondary Licenses, this 197 | License permits You to additionally distribute such Covered Software 198 | under the terms of such Secondary License(s), so that the recipient of 199 | the Larger Work may, at their option, further distribute the Covered 200 | Software under the terms of either this License or such Secondary 201 | License(s). 202 | 203 | 3.4. Notices 204 | 205 | You may not remove or alter the substance of any license notices 206 | (including copyright notices, patent notices, disclaimers of warranty, or 207 | limitations of liability) contained within the Source Code Form of the 208 | Covered Software, except that You may alter any license notices to the 209 | extent required to remedy known factual inaccuracies. 210 | 211 | 3.5. Application of Additional Terms 212 | 213 | You may choose to offer, and to charge a fee for, warranty, support, 214 | indemnity or liability obligations to one or more recipients of Covered 215 | Software. However, You may do so only on Your own behalf, and not on 216 | behalf of any Contributor. You must make it absolutely clear that any 217 | such warranty, support, indemnity, or liability obligation is offered by 218 | You alone, and You hereby agree to indemnify every Contributor for any 219 | liability incurred by such Contributor as a result of warranty, support, 220 | indemnity or liability terms You offer. You may include additional 221 | disclaimers of warranty and limitations of liability specific to any 222 | jurisdiction. 223 | 224 | 4. Inability to Comply Due to Statute or Regulation 225 | 226 | If it is impossible for You to comply with any of the terms of this License 227 | with respect to some or all of the Covered Software due to statute, 228 | judicial order, or regulation then You must: (a) comply with the terms of 229 | this License to the maximum extent possible; and (b) describe the 230 | limitations and the code they affect. Such description must be placed in a 231 | text file included with all distributions of the Covered Software under 232 | this License. Except to the extent prohibited by statute or regulation, 233 | such description must be sufficiently detailed for a recipient of ordinary 234 | skill to be able to understand it. 235 | 236 | 5. Termination 237 | 238 | 5.1. The rights granted under this License will terminate automatically if You 239 | fail to comply with any of its terms. However, if You become compliant, 240 | then the rights granted under this License from a particular Contributor 241 | are reinstated (a) provisionally, unless and until such Contributor 242 | explicitly and finally terminates Your grants, and (b) on an ongoing 243 | basis, if such Contributor fails to notify You of the non-compliance by 244 | some reasonable means prior to 60 days after You have come back into 245 | compliance. Moreover, Your grants from a particular Contributor are 246 | reinstated on an ongoing basis if such Contributor notifies You of the 247 | non-compliance by some reasonable means, this is the first time You have 248 | received notice of non-compliance with this License from such 249 | Contributor, and You become compliant prior to 30 days after Your receipt 250 | of the notice. 251 | 252 | 5.2. If You initiate litigation against any entity by asserting a patent 253 | infringement claim (excluding declaratory judgment actions, 254 | counter-claims, and cross-claims) alleging that a Contributor Version 255 | directly or indirectly infringes any patent, then the rights granted to 256 | You by any and all Contributors for the Covered Software under Section 257 | 2.1 of this License shall terminate. 258 | 259 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user 260 | license agreements (excluding distributors and resellers) which have been 261 | validly granted by You or Your distributors under this License prior to 262 | termination shall survive termination. 263 | 264 | 6. Disclaimer of Warranty 265 | 266 | Covered Software is provided under this License on an "as is" basis, 267 | without warranty of any kind, either expressed, implied, or statutory, 268 | including, without limitation, warranties that the Covered Software is free 269 | of defects, merchantable, fit for a particular purpose or non-infringing. 270 | The entire risk as to the quality and performance of the Covered Software 271 | is with You. Should any Covered Software prove defective in any respect, 272 | You (not any Contributor) assume the cost of any necessary servicing, 273 | repair, or correction. This disclaimer of warranty constitutes an essential 274 | part of this License. No use of any Covered Software is authorized under 275 | this License except under this disclaimer. 276 | 277 | 7. Limitation of Liability 278 | 279 | Under no circumstances and under no legal theory, whether tort (including 280 | negligence), contract, or otherwise, shall any Contributor, or anyone who 281 | distributes Covered Software as permitted above, be liable to You for any 282 | direct, indirect, special, incidental, or consequential damages of any 283 | character including, without limitation, damages for lost profits, loss of 284 | goodwill, work stoppage, computer failure or malfunction, or any and all 285 | other commercial damages or losses, even if such party shall have been 286 | informed of the possibility of such damages. This limitation of liability 287 | shall not apply to liability for death or personal injury resulting from 288 | such party's negligence to the extent applicable law prohibits such 289 | limitation. Some jurisdictions do not allow the exclusion or limitation of 290 | incidental or consequential damages, so this exclusion and limitation may 291 | not apply to You. 292 | 293 | 8. Litigation 294 | 295 | Any litigation relating to this License may be brought only in the courts 296 | of a jurisdiction where the defendant maintains its principal place of 297 | business and such litigation shall be governed by laws of that 298 | jurisdiction, without reference to its conflict-of-law provisions. Nothing 299 | in this Section shall prevent a party's ability to bring cross-claims or 300 | counter-claims. 301 | 302 | 9. Miscellaneous 303 | 304 | This License represents the complete agreement concerning the subject 305 | matter hereof. If any provision of this License is held to be 306 | unenforceable, such provision shall be reformed only to the extent 307 | necessary to make it enforceable. Any law or regulation which provides that 308 | the language of a contract shall be construed against the drafter shall not 309 | be used to construe this License against a Contributor. 310 | 311 | 312 | 10. Versions of the License 313 | 314 | 10.1. New Versions 315 | 316 | Mozilla Foundation is the license steward. Except as provided in Section 317 | 10.3, no one other than the license steward has the right to modify or 318 | publish new versions of this License. Each version will be given a 319 | distinguishing version number. 320 | 321 | 10.2. Effect of New Versions 322 | 323 | You may distribute the Covered Software under the terms of the version 324 | of the License under which You originally received the Covered Software, 325 | or under the terms of any subsequent version published by the license 326 | steward. 327 | 328 | 10.3. Modified Versions 329 | 330 | If you create software not governed by this License, and you want to 331 | create a new license for such software, you may create and use a 332 | modified version of this License if you rename the license and remove 333 | any references to the name of the license steward (except to note that 334 | such modified license differs from this License). 335 | 336 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 337 | Licenses If You choose to distribute Source Code Form that is 338 | Incompatible With Secondary Licenses under the terms of this version of 339 | the License, the notice described in Exhibit B of this License must be 340 | attached. 341 | 342 | Exhibit A - Source Code Form License Notice 343 | 344 | This Source Code Form is subject to the 345 | terms of the Mozilla Public License, v. 346 | 2.0. If a copy of the MPL was not 347 | distributed with this file, You can 348 | obtain one at 349 | http://mozilla.org/MPL/2.0/. 350 | 351 | If it is not possible or desirable to put the notice in a particular file, 352 | then You may include the notice in a location (such as a LICENSE file in a 353 | relevant directory) where a recipient would be likely to look for such a 354 | notice. 355 | 356 | You may add additional accurate notices of copyright ownership. 357 | 358 | Exhibit B - "Incompatible With Secondary Licenses" Notice 359 | 360 | This Source Code Form is "Incompatible 361 | With Secondary Licenses", as defined by 362 | the Mozilla Public License, v. 2.0. 363 | 364 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GOBIN := $(shell which go) 2 | GO := GO15VENDOREXPERIMENT=1 $(GOBIN) 3 | BUILDPRE := auditconstant_string.go 4 | 5 | test: $(BUILDPRE) 6 | sudo $(GO) test -v -bench=. -covermode=count -coverprofile=coverage.out 7 | 8 | profile: $(BUILDPRE) 9 | sudo $(GO) test -v -cpuprofile cpu.prof -memprofile mem.prof -bench=. 10 | 11 | auditconstant_string.go: audit_constant.go 12 | $(GO) get golang.org/x/tools/cmd/stringer 13 | $(GO) generate 14 | 15 | clean: 16 | rm -f $(BUILDPRE) 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libaudit in Go 2 | 3 | libaudit-go is a go package for interfacing with Linux audit. 4 | 5 | [![Build Status](https://travis-ci.org/mozilla/libaudit-go.svg?branch=master)](https://travis-ci.org/mozilla/libaudit-go) 6 | [![Go Report Card](https://goreportcard.com/badge/mozilla/libaudit-go "Go Report Card")](https://goreportcard.com/report/mozilla/libaudit-go) 7 | 8 | libaudit-go is a pure Go client library for interfacing with the Linux auditing framework. It provides functions 9 | to interact with the auditing subsystems over Netlink, including controlling the rule set and obtaining/interpreting 10 | incoming audit events. 11 | 12 | libaudit-go can be used to build go applications which perform tasks similar to the standard Linux auditing daemon 13 | `auditd`. 14 | 15 | To get started see package documentation at [godoc](https://godoc.org/github.com/mozilla/libaudit-go). 16 | 17 | For a simple example of usage, see the [auditprint](./auditprint/) tool included in this repository. 18 | 19 | ```bash 20 | sudo service stop auditd 21 | go get -u github.com/mozilla/libaudit-go 22 | cd $GOPATH/src/github.com/mozilla/libaudit-go 23 | go install github.com/mozilla/libaudit-go/auditprint 24 | sudo $GOPATH/bin/auditprint testdata/rules.json 25 | ``` 26 | 27 | Some key functions are discussed in the overview section below. 28 | 29 | ## Overview 30 | 31 | ### General 32 | 33 | ##### NewNetlinkConnection 34 | 35 | To use libaudit-go programs will need to initialize a new Netlink connection. `NewNetlinkConnection` can be used 36 | to allocate a new `NetlinkConnection` type which can then be passed to other functions in the library. 37 | 38 | ```go 39 | s, err := libaudit.NewNetlinkConnection() 40 | if err != nil { 41 | fmt.Printf("NewNetlinkConnection: %v\n", err) 42 | } 43 | defer s.Close() 44 | ``` 45 | 46 | `NetlinkConnection` provides a `Send` and `Receive` method to send and receive Netlink messages to the kernel, 47 | however generally applications will use the various other functions included in libaudit-go and do not need to 48 | call these functions directly. 49 | 50 | ##### GetAuditEvents 51 | 52 | GetAuditEvents starts an audit event monitor in a go-routine and returns. Programs can call this function and 53 | specify a callback function as an argument. When the audit event monitor receives a new event, this callback 54 | function will be called with the parsed `AuditEvent` as an argument. 55 | 56 | ```go 57 | 58 | func myCallback(msg *libaudit.AuditEvent, err error) { 59 | if err != nil { 60 | // An error occurred getting or parsing the audit event 61 | return 62 | } 63 | // Print the fields 64 | fmt.Println(msg.Data) 65 | // Print the raw event 66 | fmt.Println(msg.Raw) 67 | } 68 | 69 | libaudit.GetAuditEvents(s, myCallback) 70 | ``` 71 | 72 | ##### GetRawAuditEvents 73 | 74 | `GetRawAuditEvents` behaves in a similar manner to `GetAuditEvents`, however programs can use this function 75 | to instead just retrieve raw audit events from the kernel as a string, instead of having libaudit-go parse 76 | these audit events into an `AuditEvent` type. 77 | 78 | ### Audit Rules 79 | 80 | Audit rules can be loaded into the kernel using libaudit-go, however the format differs from the common rule 81 | set used by userspace tools such as auditctl/auditd. 82 | 83 | libaudit-go rulesets are defined as a JSON document. See [rules.json](./testdata/rules.json) as an example. 84 | The libaudit-go type which stores the rule set is `AuditRules`. 85 | 86 | ##### SetRules 87 | 88 | `SetRules` can be used to load an audit rule set into the kernel. The function takes a marshalled `AuditRules` 89 | type as an argument (slice of bytes), and converts the JSON based rule set into a set of audit rules suitable 90 | for submission to the kernel. 91 | 92 | The function then makes the required Netlink calls to clear the existing rule set and load the new rules. 93 | 94 | ```go 95 | // Load all rules from a file 96 | content, err := ioutil.ReadFile("audit.rules.json") 97 | if err != nil { 98 | fmt.Printf("error: %v\n", err) 99 | os.Exit(1) 100 | } 101 | 102 | // Set audit rules 103 | err = libaudit.SetRules(s, content) 104 | if err != nil { 105 | fmt.Printf("error: %v\n", err) 106 | os.Exit(1) 107 | } 108 | ``` 109 | -------------------------------------------------------------------------------- /audit_events.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package libaudit 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "strconv" 11 | "syscall" 12 | ) 13 | 14 | // EventCallback is the function definition for any function that wants to receive an AuditEvent as soon as 15 | // it is received from the kernel. Error will be set to indicate any error that occurs while receiving 16 | // messages. 17 | type EventCallback func(*AuditEvent, error) 18 | 19 | // RawEventCallback is similar to EventCallback but the difference is that the function will receive only 20 | // the message string which contains the audit event and not the parsed AuditEvent struct. 21 | type RawEventCallback func(string, error) 22 | 23 | // AuditEvent is a parsed audit message. 24 | type AuditEvent struct { 25 | Serial string // Message serial 26 | Timestamp string // Timestamp 27 | Type string // Audit event type 28 | Data map[string]string // Map of field values in the audit message 29 | Raw string // Raw audit message from kernel 30 | } 31 | 32 | // NewAuditEvent takes a NetlinkMessage passed from the netlink connection and parses the data 33 | // from the message header to return an AuditEvent type. 34 | // 35 | // Note that it is possible here that we don't have a full event to return. In some cases, a 36 | // single audit event may be represented by multiple audit events from the kernel. This function 37 | // looks after buffering partial fragments of a full event, and may only return the complete event 38 | // once an AUDIT_EOE record has been recieved for the audit event. 39 | // 40 | // See https://www.redhat.com/archives/linux-audit/2016-January/msg00019.html for additional information 41 | // on the behavior of this function. 42 | func NewAuditEvent(msg NetlinkMessage) (*AuditEvent, error) { 43 | x, err := ParseAuditEvent(string(msg.Data[:]), auditConstant(msg.Header.Type), true) 44 | if err != nil { 45 | return nil, err 46 | } 47 | if (*x).Type == "auditConstant("+strconv.Itoa(int(msg.Header.Type))+")" { 48 | return nil, fmt.Errorf("unknown message type %d", msg.Header.Type) 49 | } 50 | 51 | // Determine if the event type is one which the kernel is expected to send only a single 52 | // packet for; in these cases we don't need to look into buffering it and can return the 53 | // event immediately. 54 | if auditConstant(msg.Header.Type) < AUDIT_SYSCALL || 55 | auditConstant(msg.Header.Type) >= AUDIT_FIRST_ANOM_MSG { 56 | return x, nil 57 | } 58 | 59 | // If this is an EOE message, get the entire processed message and return it. 60 | if auditConstant(msg.Header.Type) == AUDIT_EOE { 61 | return bufferGet(x), nil 62 | } 63 | 64 | // Otherwise we need to buffer this message. 65 | bufferEvent(x) 66 | 67 | return nil, nil 68 | } 69 | 70 | // GetAuditEvents receives audit messages from the kernel and parses them into an AuditEvent. 71 | // It passes them along the callback function and if any error occurs while receiving the message, 72 | // the same will be passed in the callback as well. 73 | // 74 | // This function executes a go-routine (which does not return) and the function itself returns 75 | // immediately. 76 | func GetAuditEvents(s Netlink, cb EventCallback) { 77 | go func() { 78 | for { 79 | select { 80 | default: 81 | msgs, _ := s.Receive(false) 82 | for _, msg := range msgs { 83 | if msg.Header.Type == syscall.NLMSG_ERROR { 84 | err := int32(hostEndian.Uint32(msg.Data[0:4])) 85 | if err != 0 { 86 | cb(nil, fmt.Errorf("audit error %d", err)) 87 | } 88 | } else { 89 | nae, err := NewAuditEvent(msg) 90 | if nae == nil { 91 | continue 92 | } 93 | cb(nae, err) 94 | } 95 | } 96 | } 97 | } 98 | }() 99 | } 100 | 101 | // GetRawAuditEvents is similar to GetAuditEvents, however it returns raw messages and does not parse 102 | // incoming audit data. 103 | func GetRawAuditEvents(s Netlink, cb RawEventCallback) { 104 | go func() { 105 | for { 106 | select { 107 | default: 108 | msgs, _ := s.Receive(false) 109 | for _, msg := range msgs { 110 | var ( 111 | m string 112 | err error 113 | ) 114 | if msg.Header.Type == syscall.NLMSG_ERROR { 115 | v := int32(hostEndian.Uint32(msg.Data[0:4])) 116 | if v != 0 { 117 | cb(m, fmt.Errorf("audit error %d", v)) 118 | } 119 | } else { 120 | Type := auditConstant(msg.Header.Type) 121 | if Type.String() == "auditConstant("+strconv.Itoa(int(msg.Header.Type))+")" { 122 | err = errors.New("Unknown Type: " + string(msg.Header.Type)) 123 | } else { 124 | m = "type=" + Type.String()[6:] + 125 | " msg=" + string(msg.Data[:]) + "\n" 126 | } 127 | } 128 | cb(m, err) 129 | } 130 | } 131 | } 132 | }() 133 | } 134 | 135 | // GetAuditMessages is a blocking function (runs in forever for loop) that receives audit messages 136 | // from the kernel and parses them to AuditEvent. It passes them along the callback function and if 137 | // any error occurs while receiving the message, the same will be passed in the callback as well. 138 | // 139 | // It will return when a signal is received on the done channel. 140 | func GetAuditMessages(s Netlink, cb EventCallback, done *chan bool) { 141 | for { 142 | select { 143 | case <-*done: 144 | return 145 | default: 146 | msgs, _ := s.Receive(false) 147 | for _, msg := range msgs { 148 | if msg.Header.Type == syscall.NLMSG_ERROR { 149 | v := int32(hostEndian.Uint32(msg.Data[0:4])) 150 | if v != 0 { 151 | cb(nil, fmt.Errorf("audit error %d", v)) 152 | } 153 | } else { 154 | nae, err := NewAuditEvent(msg) 155 | if nae == nil { 156 | continue 157 | } 158 | cb(nae, err) 159 | } 160 | } 161 | } 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /auditconstant_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=auditConstant audit_constant.go"; DO NOT EDIT. 2 | 3 | package libaudit 4 | 5 | import "fmt" 6 | 7 | const _auditConstant_name = "AUDIT_COMPARE_UID_TO_OBJ_UIDAUDIT_COMPARE_GID_TO_OBJ_GIDAUDIT_COMPARE_EUID_TO_OBJ_UIDAUDIT_COMPARE_EGID_TO_OBJ_GIDAUDIT_COMPARE_AUID_TO_OBJ_UIDAUDIT_COMPARE_SUID_TO_OBJ_UIDAUDIT_COMPARE_SGID_TO_OBJ_GIDAUDIT_COMPARE_FSUID_TO_OBJ_UIDAUDIT_COMPARE_FSGID_TO_OBJ_GIDAUDIT_COMPARE_UID_TO_AUIDAUDIT_COMPARE_UID_TO_EUIDAUDIT_COMPARE_UID_TO_FSUIDAUDIT_COMPARE_UID_TO_SUIDAUDIT_COMPARE_AUID_TO_FSUIDAUDIT_COMPARE_AUID_TO_SUIDAUDIT_COMPARE_AUID_TO_EUIDAUDIT_COMPARE_EUID_TO_SUIDAUDIT_COMPARE_EUID_TO_FSUIDAUDIT_COMPARE_SUID_TO_FSUIDAUDIT_COMPARE_GID_TO_EGIDAUDIT_COMPARE_GID_TO_FSGIDAUDIT_COMPARE_GID_TO_SGIDAUDIT_COMPARE_EGID_TO_FSGIDAUDIT_COMPARE_EGID_TO_SGIDAUDIT_COMPARE_SGID_TO_FSGIDAUDIT_GETAUDIT_SETAUDIT_LISTAUDIT_ADDAUDIT_DELAUDIT_USERAUDIT_LOGINAUDIT_WATCH_INSAUDIT_WATCH_REMAUDIT_WATCH_LISTAUDIT_SIGNAL_INFOAUDIT_ADD_RULEAUDIT_DEL_RULEAUDIT_LIST_RULESAUDIT_TRIMAUDIT_MAKE_EQUIVAUDIT_TTY_GETAUDIT_TTY_SETAUDIT_SET_FEATUREAUDIT_GET_FEATUREAUDIT_FIRST_USER_MSGAUDIT_USER_ACCTAUDIT_USER_MGMTAUDIT_CRED_ACQAUDIT_CRED_DISPAUDIT_USER_STARTAUDIT_USER_ENDAUDIT_USER_AVCAUDIT_USER_CHAUTHTOKAUDIT_USER_ERRAUDIT_CRED_REFRAUDIT_USYS_CONFIGAUDIT_USER_LOGINAUDIT_USER_LOGOUTAUDIT_ADD_USERAUDIT_DEL_USERAUDIT_ADD_GROUPAUDIT_DEL_GROUPAUDIT_DAC_CHECKAUDIT_CHGRP_IDAUDIT_TESTAUDIT_TRUSTED_APPAUDIT_USER_SELINUX_ERRAUDIT_USER_CMDAUDIT_USER_TTYAUDIT_CHUSER_IDAUDIT_GRP_AUTHAUDIT_SYSTEM_BOOTAUDIT_SYSTEM_SHUTDOWNAUDIT_SYSTEM_RUNLEVELAUDIT_SERVICE_STARTAUDIT_SERVICE_STOPAUDIT_GRP_MGMTAUDIT_GRP_CHAUTHTOKAUDIT_MAC_CHECKAUDIT_ACCT_LOCKAUDIT_ACCT_UNLOCKAUDIT_LAST_USER_MSGAUDIT_FIRST_DAEMONAUDIT_DAEMON_CONFIGAUDIT_DAEMON_RECONFIGAUDIT_DAEMON_ROTATEAUDIT_DAEMON_RESUMEAUDIT_DAEMON_ACCEPTAUDIT_DAEMON_CLOSEAUDIT_LAST_DAEMONAUDIT_SYSCALLAUDIT_PATHAUDIT_IPCAUDIT_SOCKETCALLAUDIT_CONFIG_CHANGEAUDIT_SOCKADDRAUDIT_CWDAUDIT_EXECVEAUDIT_IPC_SET_PERMAUDIT_MQ_OPENAUDIT_MQ_SENDRECVAUDIT_MQ_NOTIFYAUDIT_MQ_GETSETATTRAUDIT_KERNEL_OTHERAUDIT_FD_PAIRAUDIT_OBJ_PIDAUDIT_TTYAUDIT_EOEAUDIT_BPRM_FCAPSAUDIT_CAPSETAUDIT_MMAPAUDIT_NETFILTER_PKTAUDIT_NETFILTER_CFGAUDIT_SECCOMPAUDIT_PROCTITLEAUDIT_FEATURE_CHANGEAUDIT_LAST_EVENTAUDIT_AVCAUDIT_SELINUX_ERRAUDIT_AVC_PATHAUDIT_MAC_POLICY_LOADAUDIT_MAC_STATUSAUDIT_MAC_CONFIG_CHANGEAUDIT_MAC_UNLBL_ALLOWAUDIT_MAC_CIPSOV4_ADDAUDIT_MAC_CIPSOV4_DELAUDIT_MAC_MAP_ADDAUDIT_MAC_MAP_DELAUDIT_MAC_IPSEC_ADDSAAUDIT_MAC_IPSEC_DELSAAUDIT_MAC_IPSEC_ADDSPDAUDIT_MAC_IPSEC_DELSPDAUDIT_MAC_IPSEC_EVENTAUDIT_MAC_UNLBL_STCADDAUDIT_MAC_UNLBL_STCDELAUDIT_LAST_SELINUXAUDIT_FIRST_APPARMORAUDIT_APPARMOR_AUDITAUDIT_APPARMOR_ALLOWEDAUDIT_APPARMOR_DENIEDAUDIT_APPARMOR_HTAUDIT_APPARMOR_STATUSAUDIT_APPARMOR_ERRORAUDIT_LAST_APPARMORAUDIT_FIRST_KERN_CRYPTO_MSGAUDIT_LAST_KERN_CRYPTO_MSGAUDIT_ANOM_PROMISCUOUSAUDIT_ANOM_ABENDAUDIT_ANOM_LINKAUDIT_LAST_KERN_ANOM_MSGAUDIT_INTEGRITY_FIRST_MSGAUDIT_INTEGRITY_METADATAAUDIT_INTEGRITY_STATUSAUDIT_INTEGRITY_HASHAUDIT_INTEGRITY_PCRAUDIT_INTEGRITY_RULEAUDIT_TINTEGRITY_LAST_MSGAUDIT_KERNELAUDIT_FIRST_ANOM_MSGAUDIT_ANOM_LOGIN_TIMEAUDIT_ANOM_LOGIN_SESSIONSAUDIT_ANOM_LOGIN_ACCTAUDIT_ANOM_LOGIN_LOCATIONAUDIT_ANOM_MAX_DACAUDIT_ANOM_MAX_MACAUDIT_ANOM_AMTU_FAILAUDIT_ANOM_RBAC_FAILAUDIT_ANOM_RBAC_INTEGRITY_FAILAUDIT_ANOM_CRYPTO_FAILAUDIT_ANOM_ACCESS_FSAUDIT_ANOM_EXECAUDIT_ANOM_MK_EXECAUDIT_ANOM_ADD_ACCTAUDIT_ANOM_DEL_ACCTAUDIT_ANOM_MOD_ACCTAUDIT_ANOM_ROOT_TRANSAUDIT_LAST_ANOM_MSGAUDIT_FIRST_ANOM_RESPAUDIT_RESP_ALERTAUDIT_RESP_KILL_PROCAUDIT_RESP_TERM_ACCESSAUDIT_RESP_ACCT_REMOTEAUDIT_RESP_ACCT_LOCK_TIMEDAUDIT_RESP_ACCT_UNLOCK_TIMEDAUDIT_RESP_ACCT_LOCKAUDIT_RESP_TERM_LOCKAUDIT_RESP_SEBOOLAUDIT_RESP_EXECAUDIT_RESP_SINGLEAUDIT_RESP_HALTAUDIT_LAST_ANOM_RESPAUDIT_FIRST_USER_LSPP_MSGAUDIT_ROLE_ASSIGNAUDIT_ROLE_REMOVEAUDIT_LABEL_OVERRIDEAUDIT_LABEL_LEVEL_CHANGEAUDIT_USER_LABELED_EXPORTAUDIT_USER_UNLABELED_EXPORTAUDIT_DEV_ALLOCAUDIT_DEV_DEALLOCAUDIT_FS_RELABELAUDIT_USER_MAC_POLICY_LOADAUDIT_ROLE_MODIFYAUDIT_USER_MAC_CONFIG_CHANGEAUDIT_LAST_USER_LSPP_MSGAUDIT_FIRST_CRYPTO_MSGAUDIT_CRYPTO_PARAM_CHANGE_USERAUDIT_CRYPTO_LOGINAUDIT_CRYPTO_LOGOUTAUDIT_CRYPTO_KEY_USERAUDIT_CRYPTO_FAILURE_USERAUDIT_CRYPTO_REPLAY_USERAUDIT_CRYPTO_SESSIONAUDIT_CRYPTO_IKE_SAAUDIT_CRYPTO_IPSEC_SAAUDIT_LAST_CRYPTO_MSGAUDIT_FIRST_VIRT_MSGAUDIT_VIRT_RESOURCEAUDIT_VIRT_MACHINE_IDAUDIT_LAST_VIRT_MSGAUDIT_LAST_USER_MSG2" 8 | 9 | var _auditConstant_map = map[auditConstant]string{ 10 | 1: _auditConstant_name[0:28], 11 | 2: _auditConstant_name[28:56], 12 | 3: _auditConstant_name[56:85], 13 | 4: _auditConstant_name[85:114], 14 | 5: _auditConstant_name[114:143], 15 | 6: _auditConstant_name[143:172], 16 | 7: _auditConstant_name[172:201], 17 | 8: _auditConstant_name[201:231], 18 | 9: _auditConstant_name[231:261], 19 | 10: _auditConstant_name[261:286], 20 | 11: _auditConstant_name[286:311], 21 | 12: _auditConstant_name[311:337], 22 | 13: _auditConstant_name[337:362], 23 | 14: _auditConstant_name[362:389], 24 | 15: _auditConstant_name[389:415], 25 | 16: _auditConstant_name[415:441], 26 | 17: _auditConstant_name[441:467], 27 | 18: _auditConstant_name[467:494], 28 | 19: _auditConstant_name[494:521], 29 | 20: _auditConstant_name[521:546], 30 | 21: _auditConstant_name[546:572], 31 | 22: _auditConstant_name[572:597], 32 | 23: _auditConstant_name[597:624], 33 | 24: _auditConstant_name[624:650], 34 | 25: _auditConstant_name[650:677], 35 | 1000: _auditConstant_name[677:686], 36 | 1001: _auditConstant_name[686:695], 37 | 1002: _auditConstant_name[695:705], 38 | 1003: _auditConstant_name[705:714], 39 | 1004: _auditConstant_name[714:723], 40 | 1005: _auditConstant_name[723:733], 41 | 1006: _auditConstant_name[733:744], 42 | 1007: _auditConstant_name[744:759], 43 | 1008: _auditConstant_name[759:774], 44 | 1009: _auditConstant_name[774:790], 45 | 1010: _auditConstant_name[790:807], 46 | 1011: _auditConstant_name[807:821], 47 | 1012: _auditConstant_name[821:835], 48 | 1013: _auditConstant_name[835:851], 49 | 1014: _auditConstant_name[851:861], 50 | 1015: _auditConstant_name[861:877], 51 | 1016: _auditConstant_name[877:890], 52 | 1017: _auditConstant_name[890:903], 53 | 1018: _auditConstant_name[903:920], 54 | 1019: _auditConstant_name[920:937], 55 | 1100: _auditConstant_name[937:957], 56 | 1101: _auditConstant_name[957:972], 57 | 1102: _auditConstant_name[972:987], 58 | 1103: _auditConstant_name[987:1001], 59 | 1104: _auditConstant_name[1001:1016], 60 | 1105: _auditConstant_name[1016:1032], 61 | 1106: _auditConstant_name[1032:1046], 62 | 1107: _auditConstant_name[1046:1060], 63 | 1108: _auditConstant_name[1060:1080], 64 | 1109: _auditConstant_name[1080:1094], 65 | 1110: _auditConstant_name[1094:1109], 66 | 1111: _auditConstant_name[1109:1126], 67 | 1112: _auditConstant_name[1126:1142], 68 | 1113: _auditConstant_name[1142:1159], 69 | 1114: _auditConstant_name[1159:1173], 70 | 1115: _auditConstant_name[1173:1187], 71 | 1116: _auditConstant_name[1187:1202], 72 | 1117: _auditConstant_name[1202:1217], 73 | 1118: _auditConstant_name[1217:1232], 74 | 1119: _auditConstant_name[1232:1246], 75 | 1120: _auditConstant_name[1246:1256], 76 | 1121: _auditConstant_name[1256:1273], 77 | 1122: _auditConstant_name[1273:1295], 78 | 1123: _auditConstant_name[1295:1309], 79 | 1124: _auditConstant_name[1309:1323], 80 | 1125: _auditConstant_name[1323:1338], 81 | 1126: _auditConstant_name[1338:1352], 82 | 1127: _auditConstant_name[1352:1369], 83 | 1128: _auditConstant_name[1369:1390], 84 | 1129: _auditConstant_name[1390:1411], 85 | 1130: _auditConstant_name[1411:1430], 86 | 1131: _auditConstant_name[1430:1448], 87 | 1132: _auditConstant_name[1448:1462], 88 | 1133: _auditConstant_name[1462:1481], 89 | 1134: _auditConstant_name[1481:1496], 90 | 1135: _auditConstant_name[1496:1511], 91 | 1136: _auditConstant_name[1511:1528], 92 | 1199: _auditConstant_name[1528:1547], 93 | 1200: _auditConstant_name[1547:1565], 94 | 1203: _auditConstant_name[1565:1584], 95 | 1204: _auditConstant_name[1584:1605], 96 | 1205: _auditConstant_name[1605:1624], 97 | 1206: _auditConstant_name[1624:1643], 98 | 1207: _auditConstant_name[1643:1662], 99 | 1208: _auditConstant_name[1662:1680], 100 | 1299: _auditConstant_name[1680:1697], 101 | 1300: _auditConstant_name[1697:1710], 102 | 1302: _auditConstant_name[1710:1720], 103 | 1303: _auditConstant_name[1720:1729], 104 | 1304: _auditConstant_name[1729:1745], 105 | 1305: _auditConstant_name[1745:1764], 106 | 1306: _auditConstant_name[1764:1778], 107 | 1307: _auditConstant_name[1778:1787], 108 | 1309: _auditConstant_name[1787:1799], 109 | 1311: _auditConstant_name[1799:1817], 110 | 1312: _auditConstant_name[1817:1830], 111 | 1313: _auditConstant_name[1830:1847], 112 | 1314: _auditConstant_name[1847:1862], 113 | 1315: _auditConstant_name[1862:1881], 114 | 1316: _auditConstant_name[1881:1899], 115 | 1317: _auditConstant_name[1899:1912], 116 | 1318: _auditConstant_name[1912:1925], 117 | 1319: _auditConstant_name[1925:1934], 118 | 1320: _auditConstant_name[1934:1943], 119 | 1321: _auditConstant_name[1943:1959], 120 | 1322: _auditConstant_name[1959:1971], 121 | 1323: _auditConstant_name[1971:1981], 122 | 1324: _auditConstant_name[1981:2000], 123 | 1325: _auditConstant_name[2000:2019], 124 | 1326: _auditConstant_name[2019:2032], 125 | 1327: _auditConstant_name[2032:2047], 126 | 1328: _auditConstant_name[2047:2067], 127 | 1399: _auditConstant_name[2067:2083], 128 | 1400: _auditConstant_name[2083:2092], 129 | 1401: _auditConstant_name[2092:2109], 130 | 1402: _auditConstant_name[2109:2123], 131 | 1403: _auditConstant_name[2123:2144], 132 | 1404: _auditConstant_name[2144:2160], 133 | 1405: _auditConstant_name[2160:2183], 134 | 1406: _auditConstant_name[2183:2204], 135 | 1407: _auditConstant_name[2204:2225], 136 | 1408: _auditConstant_name[2225:2246], 137 | 1409: _auditConstant_name[2246:2263], 138 | 1410: _auditConstant_name[2263:2280], 139 | 1411: _auditConstant_name[2280:2301], 140 | 1412: _auditConstant_name[2301:2322], 141 | 1413: _auditConstant_name[2322:2344], 142 | 1414: _auditConstant_name[2344:2366], 143 | 1415: _auditConstant_name[2366:2387], 144 | 1416: _auditConstant_name[2387:2409], 145 | 1417: _auditConstant_name[2409:2431], 146 | 1499: _auditConstant_name[2431:2449], 147 | 1500: _auditConstant_name[2449:2469], 148 | 1501: _auditConstant_name[2469:2489], 149 | 1502: _auditConstant_name[2489:2511], 150 | 1503: _auditConstant_name[2511:2532], 151 | 1504: _auditConstant_name[2532:2549], 152 | 1505: _auditConstant_name[2549:2570], 153 | 1506: _auditConstant_name[2570:2590], 154 | 1599: _auditConstant_name[2590:2609], 155 | 1600: _auditConstant_name[2609:2636], 156 | 1699: _auditConstant_name[2636:2662], 157 | 1700: _auditConstant_name[2662:2684], 158 | 1701: _auditConstant_name[2684:2700], 159 | 1702: _auditConstant_name[2700:2715], 160 | 1799: _auditConstant_name[2715:2739], 161 | 1800: _auditConstant_name[2739:2764], 162 | 1801: _auditConstant_name[2764:2788], 163 | 1802: _auditConstant_name[2788:2810], 164 | 1803: _auditConstant_name[2810:2830], 165 | 1804: _auditConstant_name[2830:2849], 166 | 1805: _auditConstant_name[2849:2869], 167 | 1899: _auditConstant_name[2869:2894], 168 | 2000: _auditConstant_name[2894:2906], 169 | 2100: _auditConstant_name[2906:2926], 170 | 2101: _auditConstant_name[2926:2947], 171 | 2102: _auditConstant_name[2947:2972], 172 | 2103: _auditConstant_name[2972:2993], 173 | 2104: _auditConstant_name[2993:3018], 174 | 2105: _auditConstant_name[3018:3036], 175 | 2106: _auditConstant_name[3036:3054], 176 | 2107: _auditConstant_name[3054:3074], 177 | 2108: _auditConstant_name[3074:3094], 178 | 2109: _auditConstant_name[3094:3124], 179 | 2110: _auditConstant_name[3124:3146], 180 | 2111: _auditConstant_name[3146:3166], 181 | 2112: _auditConstant_name[3166:3181], 182 | 2113: _auditConstant_name[3181:3199], 183 | 2114: _auditConstant_name[3199:3218], 184 | 2115: _auditConstant_name[3218:3237], 185 | 2116: _auditConstant_name[3237:3256], 186 | 2117: _auditConstant_name[3256:3277], 187 | 2199: _auditConstant_name[3277:3296], 188 | 2200: _auditConstant_name[3296:3317], 189 | 2201: _auditConstant_name[3317:3333], 190 | 2202: _auditConstant_name[3333:3353], 191 | 2203: _auditConstant_name[3353:3375], 192 | 2204: _auditConstant_name[3375:3397], 193 | 2205: _auditConstant_name[3397:3423], 194 | 2206: _auditConstant_name[3423:3451], 195 | 2207: _auditConstant_name[3451:3471], 196 | 2208: _auditConstant_name[3471:3491], 197 | 2209: _auditConstant_name[3491:3508], 198 | 2210: _auditConstant_name[3508:3523], 199 | 2211: _auditConstant_name[3523:3540], 200 | 2212: _auditConstant_name[3540:3555], 201 | 2299: _auditConstant_name[3555:3575], 202 | 2300: _auditConstant_name[3575:3600], 203 | 2301: _auditConstant_name[3600:3617], 204 | 2302: _auditConstant_name[3617:3634], 205 | 2303: _auditConstant_name[3634:3654], 206 | 2304: _auditConstant_name[3654:3678], 207 | 2305: _auditConstant_name[3678:3703], 208 | 2306: _auditConstant_name[3703:3730], 209 | 2307: _auditConstant_name[3730:3745], 210 | 2308: _auditConstant_name[3745:3762], 211 | 2309: _auditConstant_name[3762:3778], 212 | 2310: _auditConstant_name[3778:3804], 213 | 2311: _auditConstant_name[3804:3821], 214 | 2312: _auditConstant_name[3821:3849], 215 | 2399: _auditConstant_name[3849:3873], 216 | 2400: _auditConstant_name[3873:3895], 217 | 2401: _auditConstant_name[3895:3925], 218 | 2402: _auditConstant_name[3925:3943], 219 | 2403: _auditConstant_name[3943:3962], 220 | 2404: _auditConstant_name[3962:3983], 221 | 2405: _auditConstant_name[3983:4008], 222 | 2406: _auditConstant_name[4008:4032], 223 | 2407: _auditConstant_name[4032:4052], 224 | 2408: _auditConstant_name[4052:4071], 225 | 2409: _auditConstant_name[4071:4092], 226 | 2499: _auditConstant_name[4092:4113], 227 | 2500: _auditConstant_name[4113:4133], 228 | 2501: _auditConstant_name[4133:4152], 229 | 2502: _auditConstant_name[4152:4173], 230 | 2599: _auditConstant_name[4173:4192], 231 | 2999: _auditConstant_name[4192:4212], 232 | } 233 | 234 | func (i auditConstant) String() string { 235 | if str, ok := _auditConstant_map[i]; ok { 236 | return str 237 | } 238 | return fmt.Sprintf("auditConstant(%d)", i) 239 | } 240 | -------------------------------------------------------------------------------- /auditprint/auditprint.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | // auditprint is a simple command line tool that loads an audit rule set from a JSON file, 6 | // applies it to the current kernel and begins printing any audit event the kernel sends in 7 | // JSON format. 8 | package main 9 | 10 | import ( 11 | "encoding/json" 12 | "fmt" 13 | "io/ioutil" 14 | "os" 15 | 16 | "github.com/mozilla/libaudit-go" 17 | ) 18 | 19 | func auditProc(e *libaudit.AuditEvent, err error) { 20 | if err != nil { 21 | // See if the error is libaudit.ErrorAuditParse, if so convert and also display 22 | // the audit record we could not parse 23 | if nerr, ok := err.(libaudit.ErrorAuditParse); ok { 24 | fmt.Printf("parser error: %v: %v\n", nerr, nerr.Raw) 25 | } else { 26 | fmt.Printf("callback received error: %v\n", err) 27 | } 28 | return 29 | } 30 | // Marshal the event to JSON and print 31 | buf, err := json.Marshal(e) 32 | if err != nil { 33 | fmt.Printf("callback was unable to marshal event: %v\n", err) 34 | return 35 | } 36 | fmt.Printf("%v\n", string(buf)) 37 | } 38 | 39 | func main() { 40 | s, err := libaudit.NewNetlinkConnection() 41 | if err != nil { 42 | fmt.Fprintf(os.Stderr, "NetNetlinkConnection: %v\n", err) 43 | os.Exit(1) 44 | } 45 | 46 | if len(os.Args) != 2 { 47 | fmt.Printf("usage: %v path_to_rules.json\n", os.Args[0]) 48 | os.Exit(0) 49 | } 50 | 51 | err = libaudit.AuditSetEnabled(s, true) 52 | if err != nil { 53 | fmt.Fprintf(os.Stderr, "AuditSetEnabled: %v\n", err) 54 | os.Exit(1) 55 | } 56 | 57 | err = libaudit.AuditSetPID(s, os.Getpid()) 58 | if err != nil { 59 | fmt.Fprintf(os.Stderr, "AuditSetPid: %v\n", err) 60 | os.Exit(1) 61 | } 62 | err = libaudit.AuditSetRateLimit(s, 1000) 63 | if err != nil { 64 | fmt.Fprintf(os.Stderr, "AuditSetRateLimit: %v\n", err) 65 | os.Exit(1) 66 | } 67 | err = libaudit.AuditSetBacklogLimit(s, 250) 68 | if err != nil { 69 | fmt.Fprintf(os.Stderr, "AuditSetBacklogLimit: %v\n", err) 70 | os.Exit(1) 71 | } 72 | 73 | var ar libaudit.AuditRules 74 | buf, err := ioutil.ReadFile(os.Args[1]) 75 | if err != nil { 76 | fmt.Fprintf(os.Stderr, "ReadFile: %v\n", err) 77 | os.Exit(1) 78 | } 79 | // Make sure we can unmarshal the rules JSON to validate it is the correct 80 | // format 81 | err = json.Unmarshal(buf, &ar) 82 | if err != nil { 83 | fmt.Fprintf(os.Stderr, "Unmarshaling rules JSON: %v\n", err) 84 | os.Exit(1) 85 | } 86 | 87 | // Remove current rule set and send rules to the kernel 88 | err = libaudit.DeleteAllRules(s) 89 | if err != nil { 90 | fmt.Fprintf(os.Stderr, "DeleteAllRules: %v\n", err) 91 | os.Exit(1) 92 | } 93 | warnings, err := libaudit.SetRules(s, buf) 94 | if err != nil { 95 | fmt.Fprintf(os.Stderr, "SetRules: %v\n", err) 96 | os.Exit(1) 97 | } 98 | // Print any warnings we got back but still continue 99 | for _, x := range warnings { 100 | fmt.Fprintf(os.Stderr, "ruleset warning: %v\n", x) 101 | } 102 | 103 | doneCh := make(chan bool, 1) 104 | libaudit.GetAuditMessages(s, auditProc, &doneCh) 105 | } 106 | -------------------------------------------------------------------------------- /buffer.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package libaudit 6 | 7 | import ( 8 | "strconv" 9 | ) 10 | 11 | var bufferMap map[uint64][]*AuditEvent 12 | 13 | // bufferEvent buffers an incoming audit event which contains partial record informatioa. 14 | func bufferEvent(a *AuditEvent) { 15 | if bufferMap == nil { 16 | bufferMap = make(map[uint64][]*AuditEvent) 17 | } 18 | 19 | serial, err := strconv.ParseUint(a.Serial, 10, 64) 20 | if err != nil { 21 | return 22 | } 23 | if _, ok := bufferMap[serial]; !ok { 24 | bufferMap[serial] = make([]*AuditEvent, 5) 25 | } 26 | bufferMap[serial] = append(bufferMap[serial], a) 27 | } 28 | 29 | // bufferGet returns the complete audit event from the buffer, given the AUDIT_EOE event a. 30 | func bufferGet(a *AuditEvent) *AuditEvent { 31 | serial, err := strconv.ParseUint(a.Serial, 10, 64) 32 | if err != nil { 33 | return nil 34 | } 35 | 36 | var ( 37 | bm []*AuditEvent 38 | ok bool 39 | ) 40 | if bm, ok = bufferMap[serial]; !ok { 41 | return nil 42 | } 43 | rlen := len(a.Raw) 44 | for i := range bm { 45 | if bm[i] == nil { 46 | continue 47 | } 48 | for k, v := range bm[i].Data { 49 | a.Data[k] = v 50 | } 51 | if len(bm[i].Raw) > rlen { 52 | a.Raw += " " + bm[i].Raw[rlen:] 53 | } 54 | } 55 | 56 | delete(bufferMap, serial) 57 | return a 58 | } 59 | -------------------------------------------------------------------------------- /headers/access_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | var AccessLookUp = map[int]string{ 4 | 1: "X_OK", 5 | 2: "W_OK", 6 | 4: "R_OK", 7 | } 8 | -------------------------------------------------------------------------------- /headers/audit_x64.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // SysMapX64 is a mapping between x64 syscall names and their integer values 4 | // The list is taken from x86_64_table.h of auditd library 5 | var SysMapX64 = map[string]int{ 6 | "read": 0, 7 | "write": 1, 8 | "open": 2, 9 | "close": 3, 10 | "stat": 4, 11 | "fstat": 5, 12 | "lstat": 6, 13 | "poll": 7, 14 | "lseek": 8, 15 | "mmap": 9, 16 | "mprotect": 10, 17 | "munmap": 11, 18 | "brk": 12, 19 | "rt_sigaction": 13, 20 | "rt_sigprocmask": 14, 21 | "rt_sigreturn": 15, 22 | "ioctl": 16, 23 | "pread64": 17, 24 | "pwrite64": 18, 25 | "readv": 19, 26 | "writev": 20, 27 | "access": 21, 28 | "pipe": 22, 29 | "select": 23, 30 | "sched_yield": 24, 31 | "mremap": 25, 32 | "msync": 26, 33 | "mincore": 27, 34 | "madvise": 28, 35 | "shmget": 29, 36 | "shmat": 30, 37 | "shmctl": 31, 38 | "dup": 32, 39 | "dup2": 33, 40 | "pause": 34, 41 | "nanosleep": 35, 42 | "getitimer": 36, 43 | "alarm": 37, 44 | "setitimer": 38, 45 | "getpid": 39, 46 | "sendfile": 40, 47 | "socket": 41, 48 | "connect": 42, 49 | "accept": 43, 50 | "sendto": 44, 51 | "recvfrom": 45, 52 | "sendmsg": 46, 53 | "recvmsg": 47, 54 | "shutdown": 48, 55 | "bind": 49, 56 | "listen": 50, 57 | "getsockname": 51, 58 | "getpeername": 52, 59 | "socketpair": 53, 60 | "setsockopt": 54, 61 | "getsockopt": 55, 62 | "clone": 56, 63 | "fork": 57, 64 | "vfork": 58, 65 | "execve": 59, 66 | "exit": 60, 67 | "wait4": 61, 68 | "kill": 62, 69 | "uname": 63, 70 | "semget": 64, 71 | "semop": 65, 72 | "semctl": 66, 73 | "shmdt": 67, 74 | "msgget": 68, 75 | "msgsnd": 69, 76 | "msgrcv": 70, 77 | "msgctl": 71, 78 | "fcntl": 72, 79 | "flock": 73, 80 | "fsync": 74, 81 | "fdatasync": 75, 82 | "truncate": 76, 83 | "ftruncate": 77, 84 | "getdents": 78, 85 | "getcwd": 79, 86 | "chdir": 80, 87 | "fchdir": 81, 88 | "rename": 82, 89 | "mkdir": 83, 90 | "rmdir": 84, 91 | "creat": 85, 92 | "link": 86, 93 | "unlink": 87, 94 | "symlink": 88, 95 | "readlink": 89, 96 | "chmod": 90, 97 | "fchmod": 91, 98 | "chown": 92, 99 | "fchown": 93, 100 | "lchown": 94, 101 | "umask": 95, 102 | "gettimeofday": 96, 103 | "getrlimit": 97, 104 | "getrusage": 98, 105 | "sysinfo": 99, 106 | "times": 100, 107 | "ptrace": 101, 108 | "getuid": 102, 109 | "syslog": 103, 110 | "getgid": 104, 111 | "setuid": 105, 112 | "setgid": 106, 113 | "geteuid": 107, 114 | "getegid": 108, 115 | "setpgid": 109, 116 | "getppid": 110, 117 | "getpgrp": 111, 118 | "setsid": 112, 119 | "setreuid": 113, 120 | "setregid": 114, 121 | "getgroups": 115, 122 | "setgroups": 116, 123 | "setresuid": 117, 124 | "getresuid": 118, 125 | "setresgid": 119, 126 | "getresgid": 120, 127 | "getpgid": 121, 128 | "setfsuid": 122, 129 | "setfsgid": 123, 130 | "getsid": 124, 131 | "capget": 125, 132 | "capset": 126, 133 | "rt_sigpending": 127, 134 | "rt_sigtimedwait": 128, 135 | "rt_sigqueueinfo": 129, 136 | "rt_sigsuspend": 130, 137 | "sigaltstack": 131, 138 | "utime": 132, 139 | "mknod": 133, 140 | "uselib": 134, 141 | "personality": 135, 142 | "ustat": 136, 143 | "statfs": 137, 144 | "fstatfs": 138, 145 | "sysfs": 139, 146 | "getpriority": 140, 147 | "setpriority": 141, 148 | "sched_setparam": 142, 149 | "sched_getparam": 143, 150 | "sched_setscheduler": 144, 151 | "sched_getscheduler": 145, 152 | "sched_get_priority_max": 146, 153 | "sched_get_priority_min": 147, 154 | "sched_rr_get_interval": 148, 155 | "mlock": 149, 156 | "munlock": 150, 157 | "mlockall": 151, 158 | "munlockall": 152, 159 | "vhangup": 153, 160 | "modify_ldt": 154, 161 | "pivot_root": 155, 162 | "_sysctl": 156, 163 | "prctl": 157, 164 | "arch_prctl": 158, 165 | "adjtimex": 159, 166 | "setrlimit": 160, 167 | "chroot": 161, 168 | "sync": 162, 169 | "acct": 163, 170 | "settimeofday": 164, 171 | "mount": 165, 172 | "umount2": 166, 173 | "swapon": 167, 174 | "swapoff": 168, 175 | "reboot": 169, 176 | "sethostname": 170, 177 | "setdomainname": 171, 178 | "iopl": 172, 179 | "ioperm": 173, 180 | "create_module": 174, 181 | "init_module": 175, 182 | "delete_module": 176, 183 | "get_kernel_syms": 177, 184 | "query_module": 178, 185 | "quotactl": 179, 186 | "nfsservctl": 180, 187 | "getpmsg": 181, 188 | "putpmsg": 182, 189 | "afs_": 183, 190 | "tuxcall": 184, 191 | "security": 185, 192 | "gettid": 186, 193 | "readahead": 187, 194 | "setxattr": 188, 195 | "lsetxattr": 189, 196 | "fsetxattr": 190, 197 | "getxattr": 191, 198 | "lgetxattr": 192, 199 | "fgetxattr": 193, 200 | "listxattr": 194, 201 | "llistxattr": 195, 202 | "flistxattr": 196, 203 | "removexattr": 197, 204 | "lremovexattr": 198, 205 | "fremovexattr": 199, 206 | "tkill": 200, 207 | "time": 201, 208 | "futex": 202, 209 | "sched_setaffinity": 203, 210 | "sched_getaffinity": 204, 211 | "set_thread_area": 205, 212 | "io_setup": 206, 213 | "io_destroy": 207, 214 | "io_getevents": 208, 215 | "io_submit": 209, 216 | "io_cancel": 210, 217 | "get_thread_area": 211, 218 | "lookup_dcookie": 212, 219 | "epoll_create": 213, 220 | "epoll_ctl_old": 214, 221 | "epoll_wait_old": 215, 222 | "remap_file_pages": 216, 223 | "getdents64": 217, 224 | "set_tid_address": 218, 225 | "restart_": 219, 226 | "semtimedop": 220, 227 | "fadvise64": 221, 228 | "timer_create": 222, 229 | "timer_settime": 223, 230 | "timer_gettime": 224, 231 | "timer_getoverrun": 225, 232 | "timer_delete": 226, 233 | "clock_settime": 227, 234 | "clock_gettime": 228, 235 | "clock_getres": 229, 236 | "clock_nanosleep": 230, 237 | "exit_group": 231, 238 | "epoll_wait": 232, 239 | "epoll_ctl": 233, 240 | "tgkill": 234, 241 | "utimes": 235, 242 | "vserver": 236, 243 | "mbind": 237, 244 | "set_mempolicy": 238, 245 | "get_mempolicy": 239, 246 | "mq_open": 240, 247 | "mq_unlink": 241, 248 | "mq_timedsend": 242, 249 | "mq_timedreceive": 243, 250 | "mq_notify": 244, 251 | "mq_getsetattr": 245, 252 | "kexec_load": 246, 253 | "waitid": 247, 254 | "add_key": 248, 255 | "request_key": 249, 256 | "keyctl": 250, 257 | "ioprio_set": 251, 258 | "ioprio_get": 252, 259 | "inotify_init": 253, 260 | "inotify_add_watch": 254, 261 | "inotify_rm_watch": 255, 262 | "migrate_pages": 256, 263 | "openat": 257, 264 | "mkdirat": 258, 265 | "mknodat": 259, 266 | "fchownat": 260, 267 | "futimesat": 261, 268 | "newfstatat": 262, 269 | "unlinkat": 263, 270 | "renameat": 264, 271 | "linkat": 265, 272 | "symlinkat": 266, 273 | "readlinkat": 267, 274 | "fchmodat": 268, 275 | "faccessat": 269, 276 | "pselect6": 270, 277 | "ppoll": 271, 278 | "unshare": 272, 279 | "set_robust_list": 273, 280 | "get_robust_list": 274, 281 | "splice": 275, 282 | "tee": 276, 283 | "sync_file_range": 277, 284 | "vmsplice": 278, 285 | "move_pages": 279, 286 | "utimensat": 280, 287 | "epoll_pwait": 281, 288 | "signalfd": 282, 289 | "timerfd_create": 283, 290 | "eventfd": 284, 291 | "fallocate": 285, 292 | "timerfd_settime": 286, 293 | "timerfd_gettime": 287, 294 | "accept4": 288, 295 | "signalfd4": 289, 296 | "eventfd2": 290, 297 | "epoll_create1": 291, 298 | "dup3": 292, 299 | "pipe2": 293, 300 | "inotify_init1": 294, 301 | "preadv": 295, 302 | "pwritev": 296, 303 | "rt_tgsigqueueinfo": 297, 304 | "perf_event_open": 298, 305 | "recvmmsg": 299, 306 | "fanotify_init": 300, 307 | "fanotify_mark": 301, 308 | "prlimit64": 302, 309 | "name_to_handle_at": 303, 310 | "open_by_handle_at": 304, 311 | "clock_adjtime": 305, 312 | "syncfs": 306, 313 | "sendmmsg": 307, 314 | "setns": 308, 315 | "getcpu": 309, 316 | "process_vm_readv": 310, 317 | "process_vm_writev": 311, 318 | "kcmp": 312, 319 | "finit_module": 313, 320 | "sched_setattr": 314, 321 | "sched_getattr": 315, 322 | "renameat2": 316, 323 | "seccomp": 317, 324 | "getrandom": 318, 325 | "memfd_create": 319, 326 | "kexec_file_load": 320, 327 | "bpf": 321, 328 | "execveat": 322, 329 | "userfaultfd": 323, 330 | "membarrier": 324, 331 | "mlock2": 325, 332 | "copy_file_range": 326, 333 | } 334 | -------------------------------------------------------------------------------- /headers/audit_x64_i2s.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // ReverseSysMapX64 is a mapping between x64 syscall integer values and their names 4 | // The list is taken from x86_64_table.h of auditd library 5 | var ReverseSysMapX64 = map[string]string{ 6 | "0": "read", 7 | "1": "write", 8 | "2": "open", 9 | "3": "close", 10 | "4": "stat", 11 | "5": "fstat", 12 | "6": "lstat", 13 | "7": "poll", 14 | "8": "lseek", 15 | "9": "mmap", 16 | "10": "mprotect", 17 | "11": "munmap", 18 | "12": "brk", 19 | "13": "rt_sigaction", 20 | "14": "rt_sigprocmask", 21 | "15": "rt_sigreturn", 22 | "16": "ioctl", 23 | "17": "pread64", 24 | "18": "pwrite64", 25 | "19": "readv", 26 | "20": "writev", 27 | "21": "access", 28 | "22": "pipe", 29 | "23": "select", 30 | "24": "sched_yield", 31 | "25": "mremap", 32 | "26": "msync", 33 | "27": "mincore", 34 | "28": "madvise", 35 | "29": "shmget", 36 | "30": "shmat", 37 | "31": "shmctl", 38 | "32": "dup", 39 | "33": "dup2", 40 | "34": "pause", 41 | "35": "nanosleep", 42 | "36": "getitimer", 43 | "37": "alarm", 44 | "38": "setitimer", 45 | "39": "getpid", 46 | "40": "sendfile", 47 | "41": "socket", 48 | "42": "connect", 49 | "43": "accept", 50 | "44": "sendto", 51 | "45": "recvfrom", 52 | "46": "sendmsg", 53 | "47": "recvmsg", 54 | "48": "shutdown", 55 | "49": "bind", 56 | "50": "listen", 57 | "51": "getsockname", 58 | "52": "getpeername", 59 | "53": "socketpair", 60 | "54": "setsockopt", 61 | "55": "getsockopt", 62 | "56": "clone", 63 | "57": "fork", 64 | "58": "vfork", 65 | "59": "execve", 66 | "60": "exit", 67 | "61": "wait4", 68 | "62": "kill", 69 | "63": "uname", 70 | "64": "semget", 71 | "65": "semop", 72 | "66": "semctl", 73 | "67": "shmdt", 74 | "68": "msgget", 75 | "69": "msgsnd", 76 | "70": "msgrcv", 77 | "71": "msgctl", 78 | "72": "fcntl", 79 | "73": "flock", 80 | "74": "fsync", 81 | "75": "fdatasync", 82 | "76": "truncate", 83 | "77": "ftruncate", 84 | "78": "getdents", 85 | "79": "getcwd", 86 | "80": "chdir", 87 | "81": "fchdir", 88 | "82": "rename", 89 | "83": "mkdir", 90 | "84": "rmdir", 91 | "85": "creat", 92 | "86": "link", 93 | "87": "unlink", 94 | "88": "symlink", 95 | "89": "readlink", 96 | "90": "chmod", 97 | "91": "fchmod", 98 | "92": "chown", 99 | "93": "fchown", 100 | "94": "lchown", 101 | "95": "umask", 102 | "96": "gettimeofday", 103 | "97": "getrlimit", 104 | "98": "getrusage", 105 | "99": "sysinfo", 106 | "100": "times", 107 | "101": "ptrace", 108 | "102": "getuid", 109 | "103": "syslog", 110 | "104": "getgid", 111 | "105": "setuid", 112 | "106": "setgid", 113 | "107": "geteuid", 114 | "108": "getegid", 115 | "109": "setpgid", 116 | "110": "getppid", 117 | "111": "getpgrp", 118 | "112": "setsid", 119 | "113": "setreuid", 120 | "114": "setregid", 121 | "115": "getgroups", 122 | "116": "setgroups", 123 | "117": "setresuid", 124 | "118": "getresuid", 125 | "119": "setresgid", 126 | "120": "getresgid", 127 | "121": "getpgid", 128 | "122": "setfsuid", 129 | "123": "setfsgid", 130 | "124": "getsid", 131 | "125": "capget", 132 | "126": "capset", 133 | "127": "rt_sigpending", 134 | "128": "rt_sigtimedwait", 135 | "129": "rt_sigqueueinfo", 136 | "130": "rt_sigsuspend", 137 | "131": "sigaltstack", 138 | "132": "utime", 139 | "133": "mknod", 140 | "134": "uselib", 141 | "135": "personality", 142 | "136": "ustat", 143 | "137": "statfs", 144 | "138": "fstatfs", 145 | "139": "sysfs", 146 | "140": "getpriority", 147 | "141": "setpriority", 148 | "142": "sched_setparam", 149 | "143": "sched_getparam", 150 | "144": "sched_setscheduler", 151 | "145": "sched_getscheduler", 152 | "146": "sched_get_priority_max", 153 | "147": "sched_get_priority_min", 154 | "148": "sched_rr_get_interval", 155 | "149": "mlock", 156 | "150": "munlock", 157 | "151": "mlockall", 158 | "152": "munlockall", 159 | "153": "vhangup", 160 | "154": "modify_ldt", 161 | "155": "pivot_root", 162 | "156": "_sysctl", 163 | "157": "prctl", 164 | "158": "arch_prctl", 165 | "159": "adjtimex", 166 | "160": "setrlimit", 167 | "161": "chroot", 168 | "162": "sync", 169 | "163": "acct", 170 | "164": "settimeofday", 171 | "165": "mount", 172 | "166": "umount2", 173 | "167": "swapon", 174 | "168": "swapoff", 175 | "169": "reboot", 176 | "170": "sethostname", 177 | "171": "setdomainname", 178 | "172": "iopl", 179 | "173": "ioperm", 180 | "174": "create_module", 181 | "175": "init_module", 182 | "176": "delete_module", 183 | "177": "get_kernel_syms", 184 | "178": "query_module", 185 | "179": "quotactl", 186 | "180": "nfsservctl", 187 | "181": "getpmsg", 188 | "182": "putpmsg", 189 | "183": "afs_", 190 | "184": "tuxcall", 191 | "185": "security", 192 | "186": "gettid", 193 | "187": "readahead", 194 | "188": "setxattr", 195 | "189": "lsetxattr", 196 | "190": "fsetxattr", 197 | "191": "getxattr", 198 | "192": "lgetxattr", 199 | "193": "fgetxattr", 200 | "194": "listxattr", 201 | "195": "llistxattr", 202 | "196": "flistxattr", 203 | "197": "removexattr", 204 | "198": "lremovexattr", 205 | "199": "fremovexattr", 206 | "200": "tkill", 207 | "201": "time", 208 | "202": "futex", 209 | "203": "sched_setaffinity", 210 | "204": "sched_getaffinity", 211 | "205": "set_thread_area", 212 | "206": "io_setup", 213 | "207": "io_destroy", 214 | "208": "io_getevents", 215 | "209": "io_submit", 216 | "210": "io_cancel", 217 | "211": "get_thread_area", 218 | "212": "lookup_dcookie", 219 | "213": "epoll_create", 220 | "214": "epoll_ctl_old", 221 | "215": "epoll_wait_old", 222 | "216": "remap_file_pages", 223 | "217": "getdents64", 224 | "218": "set_tid_address", 225 | "219": "restart_", 226 | "220": "semtimedop", 227 | "221": "fadvise64", 228 | "222": "timer_create", 229 | "223": "timer_settime", 230 | "224": "timer_gettime", 231 | "225": "timer_getoverrun", 232 | "226": "timer_delete", 233 | "227": "clock_settime", 234 | "228": "clock_gettime", 235 | "229": "clock_getres", 236 | "230": "clock_nanosleep", 237 | "231": "exit_group", 238 | "232": "epoll_wait", 239 | "233": "epoll_ctl", 240 | "234": "tgkill", 241 | "235": "utimes", 242 | "236": "vserver", 243 | "237": "mbind", 244 | "238": "set_mempolicy", 245 | "239": "get_mempolicy", 246 | "240": "mq_open", 247 | "241": "mq_unlink", 248 | "242": "mq_timedsend", 249 | "243": "mq_timedreceive", 250 | "244": "mq_notify", 251 | "245": "mq_getsetattr", 252 | "246": "kexec_load", 253 | "247": "waitid", 254 | "248": "add_key", 255 | "249": "request_key", 256 | "250": "keyctl", 257 | "251": "ioprio_set", 258 | "252": "ioprio_get", 259 | "253": "inotify_init", 260 | "254": "inotify_add_watch", 261 | "255": "inotify_rm_watch", 262 | "256": "migrate_pages", 263 | "257": "openat", 264 | "258": "mkdirat", 265 | "259": "mknodat", 266 | "260": "fchownat", 267 | "261": "futimesat", 268 | "262": "newfstatat", 269 | "263": "unlinkat", 270 | "264": "renameat", 271 | "265": "linkat", 272 | "266": "symlinkat", 273 | "267": "readlinkat", 274 | "268": "fchmodat", 275 | "269": "faccessat", 276 | "270": "pselect6", 277 | "271": "ppoll", 278 | "272": "unshare", 279 | "273": "set_robust_list", 280 | "274": "get_robust_list", 281 | "275": "splice", 282 | "276": "tee", 283 | "277": "sync_file_range", 284 | "278": "vmsplice", 285 | "279": "move_pages", 286 | "280": "utimensat", 287 | "281": "epoll_pwait", 288 | "282": "signalfd", 289 | "283": "timerfd_create", 290 | "284": "eventfd", 291 | "285": "fallocate", 292 | "286": "timerfd_settime", 293 | "287": "timerfd_gettime", 294 | "288": "accept4", 295 | "289": "signalfd4", 296 | "290": "eventfd2", 297 | "291": "epoll_create1", 298 | "292": "dup3", 299 | "293": "pipe2", 300 | "294": "inotify_init1", 301 | "295": "preadv", 302 | "296": "pwritev", 303 | "297": "rt_tgsigqueueinfo", 304 | "298": "perf_event_open", 305 | "299": "recvmmsg", 306 | "300": "fanotify_init", 307 | "301": "fanotify_mark", 308 | "302": "prlimit64", 309 | "303": "name_to_handle_at", 310 | "304": "open_by_handle_at", 311 | "305": "clock_adjtime", 312 | "306": "syncfs", 313 | "307": "sendmmsg", 314 | "308": "setns", 315 | "309": "getcpu", 316 | "310": "process_vm_readv", 317 | "311": "process_vm_writev", 318 | "312": "kcmp", 319 | "313": "finit_module", 320 | "314": "sched_setattr", 321 | "315": "sched_getattr", 322 | "316": "renameat2", 323 | "317": "seccomp", 324 | "318": "getrandom", 325 | "319": "memfd_create", 326 | "320": "kexec_file_load", 327 | "321": "bpf", 328 | "322": "execveat", 329 | "323": "userfaultfd", 330 | "324": "membarrier", 331 | "325": "mlock2", 332 | "326": "copy_file_range", 333 | } 334 | -------------------------------------------------------------------------------- /headers/cap_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | //Location: include/uapi/linux/capability.h 4 | var CapabLookup = map[int]string{ 5 | 0: "chown", 6 | 1: "dac_override", 7 | 2: "dac_read_search", 8 | 3: "fowner", 9 | 4: "fsetid", 10 | 5: "kill", 11 | 6: "setgid", 12 | 7: "setuid", 13 | 8: "setpcap", 14 | 9: "linux_immutable", 15 | 10: "net_bind_service", 16 | 11: "net_broadcast", 17 | 12: "net_admin", 18 | 13: "net_raw", 19 | 14: "ipc_lock", 20 | 15: "ipc_owner", 21 | 16: "sys_module", 22 | 17: "sys_rawio", 23 | 18: "sys_chroot", 24 | 19: "sys_ptrace", 25 | 20: "sys_pacct", 26 | 21: "sys_admin", 27 | 22: "sys_boot", 28 | 23: "sys_nice", 29 | 24: "sys_resource", 30 | 25: "sys_time", 31 | 26: "sys_tty_config", 32 | 27: "mknod", 33 | 28: "lease", 34 | 29: "audit_write", 35 | 30: "audit_control", 36 | 31: "setfcap", 37 | 32: "mac_override", 38 | 33: "mac_admin", 39 | 34: "syslog", 40 | 35: "wake_alarm", 41 | 36: "block_suspend", 42 | 37: "audit_read", 43 | } 44 | -------------------------------------------------------------------------------- /headers/clock_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | //Location: include/uapi/linux/time.h 4 | var ClockLookup = map[int]string{ 5 | 0: "CLOCK_REALTIME", 6 | 1: "CLOCK_MONOTONIC", 7 | 2: "CLOCK_PROCESS_CPUTIME_ID", 8 | 3: "CLOCK_THREAD_CPUTIME_ID", 9 | 4: "CLOCK_MONOTONIC_RAW", 10 | 5: "CLOCK_REALTIME_COARSE", 11 | 6: "CLOCK_MONOTONIC_COARSE", 12 | 7: "CLOCK_BOOTTIME", 13 | 8: "CLOCK_REALTIME_ALARM", 14 | 9: "CLOCK_BOOTTIME_ALARM", 15 | 10: "CLOCK_SGI_CYCLE", 16 | 11: "CLOCK_TAI", 17 | } 18 | -------------------------------------------------------------------------------- /headers/cloneflag_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/uapi/linux/sched.h 4 | var CloneLookUp = map[int]string{ 5 | 0x00000100: "CLONE_VM", 6 | 0x00000200: "CLONE_FS", 7 | 0x00000400: "CLONE_FILES", 8 | 0x00000800: "CLONE_SIGHAND", 9 | 0x00002000: "CLONE_PTRACE", 10 | 0x00004000: "CLONE_VFORK", 11 | 0x00008000: "CLONE_PARENT", 12 | 0x00010000: "CLONE_THREAD", 13 | 0x00020000: "CLONE_NEWNS", 14 | 0x00040000: "CLONE_SYSVSEM", 15 | 0x00080000: "CLONE_SETTLS", 16 | 0x00100000: "CLONE_PARENT_SETTID", 17 | 0x00200000: "CLONE_CHILD_CLEARTID", 18 | 0x00400000: "CLONE_DETACHED", 19 | 0x00800000: "CLONE_UNTRACED", 20 | 0x01000000: "CLONE_CHILD_SETTID", 21 | 0x02000000: "CLONE_STOPPED", 22 | 0x04000000: "CLONE_NEWUTS", 23 | 0x08000000: "CLONE_NEWIPC", 24 | 0x10000000: "CLONE_NEWUSER", 25 | 0x20000000: "CLONE_NEWPID", 26 | 0x40000000: "CLONE_NEWNET", 27 | 0x80000000: "CLONE_IO", 28 | } 29 | -------------------------------------------------------------------------------- /headers/epollctl_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/uapi/linux/eventpoll.h 4 | var EpollLookup = map[int]string{ 5 | 1: "EPOLL_CTL_ADD", 6 | 2: "EPOLL_CTL_DEL", 7 | 3: "EPOLL_CTL_MOD", 8 | } 9 | -------------------------------------------------------------------------------- /headers/fcntl_cmd_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/uapi/asm-generic/fcntl.h <17 4 | // include/uapi/linux/fcntl.h >= 1024 5 | var FcntlLookup = map[int]string{ 6 | 0: "F_DUPFD", 7 | 1: "F_GETFD", 8 | 2: "F_SETFD", 9 | 3: "F_GETFL", 10 | 4: "F_SETFL", 11 | 5: "F_GETLK", 12 | 6: "F_SETLK", 13 | 7: "F_SETLKW", 14 | 8: "F_SETOWN", 15 | 9: "F_GETOWN", 16 | 10: "F_SETSIG", 17 | 11: "F_GETSIG", 18 | 12: "F_GETLK64", 19 | 13: "F_SETLK64", 20 | 14: "F_SETLKW64", 21 | 15: "F_SETOWN_EX", 22 | 16: "F_GETOWN_EX", 23 | 17: "F_GETOWNER_UIDS", 24 | 1024: "F_SETLEASE", 25 | 1025: "F_GETLEASE", 26 | 1026: "F_NOTIFY", 27 | 1029: "F_CANCELLK", 28 | 1030: "F_DUPFD_CLOEXEC", 29 | 1031: "F_SETPIPE_SZ", 30 | 1032: "F_GETPIPE_SZ", 31 | 1033: "F_ADD_SEALS", 32 | 1034: "F_GET_SEALS", 33 | } 34 | -------------------------------------------------------------------------------- /headers/field_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | var FieldMap = map[string]int{ 4 | "pid": 0, 5 | "uid": 1, 6 | "euid": 2, 7 | "suid": 3, 8 | "fsuid": 4, 9 | "gid": 5, 10 | "egid": 6, 11 | "sgid": 7, 12 | "fsgid": 8, 13 | "auid": 9, 14 | "loginuid": 9, 15 | "pers": 10, 16 | "arch": 11, 17 | "msgtype": 12, 18 | "subj_user": 13, 19 | "subj_role": 14, 20 | "subj_type": 15, 21 | "subj_sen": 16, 22 | "subj_clr": 17, 23 | "ppid": 18, 24 | "obj_user": 19, 25 | "obj_role": 20, 26 | "obj_type": 21, 27 | "obj_lev_low": 22, 28 | "obj_lev_high": 23, 29 | "devmajor": 100, 30 | "devminor": 101, 31 | "inode": 102, 32 | "exit": 103, 33 | "success": 104, 34 | "path": 105, 35 | "perm": 106, 36 | "dir": 107, 37 | "filetype": 108, 38 | "obj_uid": 109, 39 | "obj_gid": 110, 40 | "field_compare": 111, 41 | "a0": 200, 42 | "a1": 201, 43 | "a2": 202, 44 | "a3": 203, 45 | "key": 210, 46 | } 47 | -------------------------------------------------------------------------------- /headers/ftype_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | var FtypeTab = map[string]int{ 4 | "block": 24576, 5 | "character": 8192, 6 | "dir": 16384, 7 | "fifo": 4096, 8 | "file": 32768, 9 | "link": 40960, 10 | "socket": 49152, 11 | } -------------------------------------------------------------------------------- /headers/icmptype_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/uapi/linux/icmp.h 4 | var IcmpLookup = map[int]string{ 5 | 0: "echo-reply", 6 | 3: "destination-unreachable", 7 | 4: "source-quench", 8 | 5: "redirect", 9 | 8: "echo", 10 | 11: "time-exceeded", 11 | 12: "parameter-problem", 12 | 13: "timestamp-request", 13 | 14: "timestamp-reply", 14 | 15: "info-request", 15 | 16: "info-reply", 16 | 17: "address-mask-request", 17 | 18: "address-mask-reply", 18 | } 19 | -------------------------------------------------------------------------------- /headers/ioctlreq_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/uapi/linux/kd.h 4 | // include/uapi/linux/cdrom.h 5 | // include/uapi/asm-generic/ioctls.h 6 | // include/uapi/drm/drm.h 7 | 8 | var IoctlLookup = map[int]string{ 9 | 0x4B3A: "KDSETMODE", 10 | 0x4B3B: "KDGETMODE", 11 | 0x5309: "CDROMEJECT", 12 | 0x530F: "CDROMEJECT_SW", 13 | 0x5311: "CDROM_GET_UPC", 14 | 0x5316: "CDROMSEEK", 15 | 0x5401: "TCGETS", 16 | 0x5402: "TCSETS", 17 | 0x5403: "TCSETSW", 18 | 0x5404: "TCSETSF", 19 | 0x5409: "TCSBRK", 20 | 0x540B: "TCFLSH", 21 | 0x540E: "TIOCSCTTY", 22 | 0x540F: "TIOCGPGRP", 23 | 0x5410: "TIOCSPGRP", 24 | 0x5413: "TIOCGWINSZ", 25 | 0x5414: "TIOCSWINSZ", 26 | 0x541B: "TIOCINQ", 27 | 0x5421: "FIONBIO", 28 | 0x8901: "FIOSETOWN", 29 | 0x8903: "FIOGETOWN", 30 | 0x8910: "SIOCGIFNAME", 31 | 0x8927: "SIOCGIFHWADDR", 32 | 0x8933: "SIOCGIFINDEX", 33 | 0x89a2: "SIOCBRADDIF", 34 | 0x40045431: "TIOCSPTLCK", 35 | 0x80045430: "TIOCGPTN", 36 | 0x80045431: "TIOCSPTLCK", 37 | 0xC01C64A3: "DRM_IOCTL_MODE_CURSOR", 38 | 0xC01864B0: "DRM_IOCTL_MODE_PAGE_FLIP", 39 | 0xC01864B1: "DRM_IOCTL_MODE_DIRTYFB"} 40 | -------------------------------------------------------------------------------- /headers/ip6optname_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/uapi/linux/in6.h 4 | // include/uapi/linux/netfilter_ipv6/ip6_tables.h 5 | // include/uapi/linux/mroute6.h 6 | 7 | var Ip6OptLookup = map[int]string{ 8 | 1: "IPV6_ADDRFORM", 9 | 2: "IPV6_2292PKTINFO", 10 | 3: "IPV6_2292HOPOPTS", 11 | 4: "IPV6_2292DSTOPTS", 12 | 5: "IPV6_2292RTHDR", 13 | 6: "IPV6_2292PKTOPTIONS", 14 | 7: "IPV6_CHECKSUM", 15 | 8: "IPV6_2292HOPLIMIT", 16 | 9: "IPV6_NEXTHOP", 17 | 10: "IPV6_AUTHHDR", 18 | 11: "IPV6_FLOWINFO", 19 | 16: "IPV6_UNICAST_HOPS", 20 | 17: "IPV6_MULTICAST_IF", 21 | 18: "IPV6_MULTICAST_HOPS", 22 | 19: "IPV6_MULTICAST_LOOP", 23 | 20: "IPV6_ADD_MEMBERSHIP", 24 | 21: "IPV6_DROP_MEMBERSHIP", 25 | 22: "IPV6_ROUTER_ALERT", 26 | 23: "IPV6_MTU_DISCOVER", 27 | 24: "IPV6_MTU", 28 | 25: "IPV6_RECVERR", 29 | 26: "IPV6_V6ONLY", 30 | 27: "IPV6_JOIN_ANYCAST", 31 | 28: "IPV6_LEAVE_ANYCAST", 32 | 32: "IPV6_FLOWLABEL_MGR", 33 | 33: "IPV6_FLOWINFO_SEND", 34 | 34: "IPV6_IPSEC_POLICY", 35 | 35: "IPV6_XFRM_POLICY", 36 | 42: "MCAST_JOIN_GROUP", 37 | 43: "MCAST_BLOCK_SOURCE", 38 | 44: "MCAST_UNBLOCK_SOURCE", 39 | 45: "MCAST_LEAVE_GROUP", 40 | 46: "MCAST_JOIN_SOURCE_GROUP", 41 | 47: "MCAST_LEAVE_SOURCE_GROUP", 42 | 48: "MCAST_MSFILTER", 43 | 49: "IPV6_RECVPKTINFO", 44 | 50: "IPV6_PKTINFO", 45 | 51: "IPV6_RECVHOPLIMIT", 46 | 52: "IPV6_HOPLIMIT", 47 | 53: "IPV6_RECVHOPOPTS", 48 | 54: "IPV6_HOPOPTS", 49 | 55: "IPV6_RTHDRDSTOPTS", 50 | 56: "IPV6_RECVRTHDR", 51 | 57: "IPV6_RTHDR", 52 | 58: "IPV6_RECVDSTOPTS", 53 | 59: "IPV6_DSTOPTS", 54 | 60: "IPV6_RECVPATHMTU", 55 | 61: "IPV6_PATHMTU", 56 | 62: "IPV6_DONTFRAG", 57 | 63: "IPV6_USE_MIN_MTU", 58 | 64: "IP6T_SO_SET_REPLACE", 59 | 65: "IP6T_SO_SET_ADD_COUNTERS", 60 | 66: "IPV6_RECVTCLASS", 61 | 67: "IPV6_TCLASS", 62 | 68: "IP6T_SO_GET_REVISION_MATCH", 63 | 69: "IP6T_SO_GET_REVISION_TARGET", 64 | 72: "IPV6_ADDR_PREFERENCES", 65 | 73: "IPV6_MINHOPCOUNT", 66 | 74: "IPV6_ORIGDSTADDR", 67 | 75: "IPV6_TRANSPARENT", 68 | 76: "IPV6_UNICAST_IF", 69 | 80: "IP6T_SO_ORIGINAL_DST", 70 | } 71 | -------------------------------------------------------------------------------- /headers/ipc_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | import "syscall" 4 | 5 | // Location: include/uapi/linux/ipc.h 6 | var IpccallLookup = map[int]string{ 7 | syscall.SYS_SEMOP: "semop", 8 | syscall.SYS_SEMGET: "semget", 9 | syscall.SYS_SEMCTL: "semctl", 10 | 4: "semtimedop", 11 | syscall.SYS_MSGSND: "msgsnd", 12 | syscall.SYS_MSGRCV: "msgrcv", 13 | syscall.SYS_MSGGET: "msgget", 14 | syscall.SYS_MSGCTL: "msgctl", 15 | syscall.SYS_SHMAT: "shmat", 16 | syscall.SYS_SHMDT: "shmdt", 17 | syscall.SYS_SHMGET: "shmget", 18 | syscall.SYS_SHMCTL: "shmctl", 19 | } 20 | -------------------------------------------------------------------------------- /headers/ipoptname_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/uapi/linux/in.h 4 | // include/uapi/linux/netfilter_ipv4/ip_tables.h 5 | var IpOptLookup = map[int]string{ 6 | 1: "IP_TOS", 7 | 2: "IP_TTL", 8 | 3: "IP_HDRINCL", 9 | 4: "IP_OPTIONS", 10 | 5: "IP_ROUTER_ALERT", 11 | 6: "IP_RECVOPTS", 12 | 7: "IP_RETOPTS", 13 | 8: "IP_PKTINFO", 14 | 9: "IP_PKTOPTIONS", 15 | 10: "IP_MTU_DISCOVER", 16 | 11: "IP_RECVERR", 17 | 12: "IP_RECVTTL", 18 | 14: "IP_MTU", 19 | 15: "IP_FREEBIND", 20 | 16: "IP_IPSEC_POLICY", 21 | 17: "IP_XFRM_POLICY", 22 | 18: "IP_PASSSEC", 23 | 19: "IP_TRANSPARENT", 24 | 20: "IP_ORIGDSTADDR", 25 | 21: "IP_MINTTL", 26 | 22: "IP_NODEFRAG", 27 | 23: "IP_CHECKSUM", 28 | 32: "IP_MULTICAST_IF", 29 | 33: "IP_MULTICAST_TTL", 30 | 34: "IP_MULTICAST_LOOP", 31 | 35: "IP_ADD_MEMBERSHIP", 32 | 36: "IP_DROP_MEMBERSHIP", 33 | 37: "IP_UNBLOCK_SOURCE", 34 | 38: "IP_BLOCK_SOURCE", 35 | 39: "IP_ADD_SOURCE_MEMBERSHIP", 36 | 40: "IP_DROP_SOURCE_MEMBERSHIP", 37 | 41: "IP_MSFILTER", 38 | 42: "MCAST_JOIN_GROUP", 39 | 43: "MCAST_BLOCK_SOURCE", 40 | 44: "MCAST_UNBLOCK_SOURCE", 41 | 45: "MCAST_LEAVE_GROUP", 42 | 46: "MCAST_JOIN_SOURCE_GROUP", 43 | 47: "MCAST_LEAVE_SOURCE_GROUP", 44 | 48: "MCAST_MSFILTER", 45 | 49: "IP_MULTICAST_ALL", 46 | 50: "IP_UNICAST_IF", 47 | 64: "IPT_SO_SET_REPLACE", 48 | 65: "IPT_SO_SET_ADD_COUNTERS", 49 | 66: "IPT_SO_GET_REVISION_TARGET", 50 | } 51 | -------------------------------------------------------------------------------- /headers/mmap_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/uapi/asm-generic/mman.h >0x100 4 | // include/uapi/asm-generic/mman-common.h < 0x100 5 | var MmapLookUp = map[int]string{ 6 | 0x00001: "MAP_SHARED", 7 | 0x00002: "MAP_PRIVATE", 8 | 0x00010: "MAP_FIXED", 9 | 0x00020: "MAP_ANONYMOUS", 10 | 0x00040: "MAP_32BIT", 11 | 0x00100: "MAP_GROWSDOWN", 12 | 0x00800: "MAP_DENYWRITE", 13 | 0x01000: "MAP_EXECUTABLE", 14 | 0x02000: "MAP_LOCKED", 15 | 0x04000: "MAP_NORESERVE", 16 | 0x08000: "MAP_POPULATE", 17 | 0x10000: "MAP_NONBLOCK", 18 | 0x20000: "MAP_STACK", 19 | 0x40000: "MAP_HUGETLB", 20 | } 21 | -------------------------------------------------------------------------------- /headers/mount_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | import "syscall" 4 | 5 | // Location: include/uapi/linux/fs.h 6 | // when updating look at printMount 7 | var MountLookUp = map[int]string{ 8 | syscall.MS_RDONLY: "MS_RDONLY", 9 | syscall.MS_NOSUID: "MS_NOSUID", 10 | syscall.MS_NODEV: "MS_NODEV", 11 | syscall.MS_NOEXEC: "MS_NOEXEC", 12 | syscall.MS_SYNCHRONOUS: "MS_SYNCHRONOUS", 13 | syscall.MS_REMOUNT: "MS_REMOUNT", 14 | syscall.MS_MANDLOCK: "MS_MANDLOCK", 15 | syscall.MS_DIRSYNC: "MS_DIRSYNC", 16 | syscall.MS_NOATIME: "MS_NOATIME", 17 | syscall.MS_NODIRATIME: "MS_NODIRATIME", 18 | syscall.MS_BIND: "MS_BIND", 19 | syscall.MS_MOVE: "MS_MOVE", 20 | syscall.MS_REC: "MS_REC", 21 | syscall.MS_SILENT: "MS_SILENT", 22 | syscall.MS_POSIXACL: "MS_POSIXACL", 23 | syscall.MS_UNBINDABLE: "MS_UNBINDABLE", 24 | syscall.MS_PRIVATE: "MS_PRIVATE", 25 | syscall.MS_SLAVE: "MS_SLAVE", 26 | syscall.MS_SHARED: "MS_SHARED", 27 | syscall.MS_RELATIME: "MS_RELATIME", 28 | syscall.MS_KERNMOUNT: "MS_KERNMOUNT", 29 | syscall.MS_I_VERSION: "MS_I_VERSION", 30 | 1 << 24: "MS_STRICTATIME", 31 | 1 << 27: "MS_SNAP_STABLE", 32 | 1 << 28: "MS_NOSEC", 33 | 1 << 29: "MS_BORN", 34 | syscall.MS_ACTIVE: "MS_ACTIVE", 35 | syscall.MS_NOUSER: "MS_NOUSER", 36 | } 37 | -------------------------------------------------------------------------------- /headers/nfproto_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | //Location: include/uapi/linux/netfilter.h 4 | var NfProtoLookup = map[int]string{ 5 | 0: "unspecified", 6 | 1: "inet", 7 | 2: "ipv4", 8 | 3: "arp", 9 | 7: "bridge", 10 | 10: "ipv6", 11 | 12: "decnet", 12 | } 13 | -------------------------------------------------------------------------------- /headers/pktoptname_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/uapi/linux/if_packet.h 4 | var PktOptLookup = map[int]string{ 5 | 1: "PACKET_ADD_MEMBERSHIP", 6 | 2: "PACKET_DROP_MEMBERSHIP", 7 | 3: "PACKET_RECV_OUTPUT", 8 | 5: "PACKET_RX_RING", 9 | 6: "PACKET_STATISTICS", 10 | 7: "PACKET_COPY_THRESH", 11 | 8: "PACKET_AUXDATA", 12 | 9: "PACKET_ORIGDEV", 13 | 10: "PACKET_VERSION", 14 | 11: "PACKET_HDRLEN", 15 | 12: "PACKET_RESERVE", 16 | 13: "PACKET_TX_RING", 17 | 14: "PACKET_LOSS", 18 | 15: "PACKET_VNET_HDR", 19 | 16: "PACKET_TX_TIMESTAMP", 20 | 17: "PACKET_TIMESTAMP", 21 | 18: "PACKET_FANOUT", 22 | 19: "PACKET_TX_HAS_OFF", 23 | 20: "PACKET_QDISC_BYPASS", 24 | } 25 | -------------------------------------------------------------------------------- /headers/prctl_opt_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/uapi/linux/prctl.h 4 | 5 | var PrctlLookup = map[int]string{ 6 | 1: "PR_SET_PDEATHSIG", 7 | 2: "PR_GET_PDEATHSIG", 8 | 3: "PR_GET_DUMPABLE", 9 | 4: "PR_SET_DUMPABLE", 10 | 5: "PR_GET_UNALIGN", 11 | 6: "PR_SET_UNALIGN", 12 | 7: "PR_GET_KEEPCAPS", 13 | 8: "PR_SET_KEEPCAPS", 14 | 9: "PR_GET_FPEMU", 15 | 10: "PR_SET_FPEMU", 16 | 11: "PR_GET_FPEXC", 17 | 12: "PR_SET_FPEXC", 18 | 13: "PR_GET_TIMING", 19 | 14: "PR_SET_TIMING", 20 | 15: "PR_SET_NAME", 21 | 16: "PR_GET_NAME", 22 | 19: "PR_GET_ENDIAN", 23 | 20: "PR_SET_ENDIAN", 24 | 21: "PR_GET_SECCOMP", 25 | 22: "PR_SET_SECCOMP", 26 | 23: "PR_CAPBSET_READ", 27 | 24: "PR_CAPBSET_DROP", 28 | 25: "PR_GET_TSC", 29 | 26: "PR_SET_TSC", 30 | 27: "PR_GET_SECUREBITS", 31 | 28: "PR_SET_SECUREBITS", 32 | 29: "PR_SET_TIMERSLACK", 33 | 30: "PR_GET_TIMERSLACK", 34 | 31: "PR_TASK_PERF_EVENTS_DISABLE", 35 | 32: "PR_TASK_PERF_EVENTS_ENABLE", 36 | 33: "PR_MCE_KILL", 37 | 34: "PR_MCE_KILL_GET", 38 | 35: "PR_SET_MM", 39 | 36: "PR_SET_CHILD_SUBREAPER", 40 | 37: "PR_GET_CHILD_SUBREAPER", 41 | 38: "PR_SET_NO_NEW_PRIVS", 42 | 39: "PR_GET_NO_NEW_PRIVS", 43 | 40: "PR_GET_TID_ADDRESS", 44 | 41: "PR_SET_THP_DISABLE", 45 | 42: "PR_GET_THP_DISABLE", 46 | 43: "PR_MPX_ENABLE_MANAGEMENT", 47 | 44: "PR_MPX_DISABLE_MANAGEMENT", 48 | 45: "PR_SET_FP_MODE", 49 | 46: "PR_GET_FP_MODE", 50 | 47: "PR_CAP_AMBIENT", 51 | } 52 | -------------------------------------------------------------------------------- /headers/protocol_tab.go: -------------------------------------------------------------------------------- 1 | // Location: include/uapi/asm-generic/mman-common.h 2 | 3 | package headers 4 | 5 | var ProtLookUp = map[int]string{ 6 | 1: "PROT_READ", 7 | 2: "PROT_WRITE", 8 | 4: "PROT_EXEC", 9 | 8: "PROT_SEM", 10 | } 11 | -------------------------------------------------------------------------------- /headers/ptrace_tab.go: -------------------------------------------------------------------------------- 1 | // Location: include/uapi/linux/ptrace.h 2 | 3 | package headers 4 | 5 | var PtraceLookup = map[int]string{ 6 | 0: "PTRACE_TRACEME", 7 | 1: "PTRACE_PEEKTEXT", 8 | 2: "PTRACE_PEEKDATA", 9 | 3: "PTRACE_PEEKUSER", 10 | 4: "PTRACE_POKETEXT", 11 | 5: "PTRACE_POKEDATA", 12 | 6: "PTRACE_POKEUSER", 13 | 7: "PTRACE_CONT", 14 | 8: "PTRACE_KILL", 15 | 9: "PTRACE_SINGLESTEP", 16 | 12: "PTRACE_GETREGS", 17 | 13: "PTRACE_SETREGS", 18 | 14: "PTRACE_GETFPREGS", 19 | 15: "PTRACE_SETFPREGS", 20 | 16: "PTRACE_ATTACH", 21 | 17: "PTRACE_DETACH", 22 | 18: "PTRACE_GETFPXREGS", 23 | 19: "PTRACE_SETFPXREGS", 24 | 24: "PTRACE_SYSCALL", 25 | 0x4200: "PTRACE_SETOPTIONS", 26 | 0x4201: "PTRACE_GETEVENTMSG", 27 | 0x4202: "PTRACE_GETSIGINFO", 28 | 0x4203: "PTRACE_SETSIGINFO", 29 | 0x4204: "PTRACE_GETREGSET", 30 | 0x4205: "PTRACE_SETREGSET", 31 | 0x4206: "PTRACE_SEIZE", 32 | 0x4207: "PTRACE_INTERRUPT", 33 | 0x4208: "PTRACE_LISTEN", 34 | 0x4209: "PTRACE_PEEKSIGINFO", 35 | 0x420a: "PTRACE_GETSIGMASK", 36 | 0x420b: "PTRACE_SETSIGMASK", 37 | } 38 | -------------------------------------------------------------------------------- /headers/recv_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/linux/socket.h 4 | var RecvLookUp = map[int]string{ 5 | 0x00000001: "MSG_OOB", 6 | 0x00000002: "MSG_PEEK", 7 | 0x00000004: "MSG_DONTROUTE", 8 | 0x00000008: "MSG_CTRUNC", 9 | 0x00000010: "MSG_PROXY", 10 | 0x00000020: "MSG_TRUNC", 11 | 0x00000040: "MSG_DONTWAIT", 12 | 0x00000080: "MSG_EOR", 13 | 0x00000100: "MSG_WAITALL", 14 | 0x00000200: "MSG_FIN", 15 | 0x00000400: "MSG_SYN", 16 | 0x00000800: "MSG_CONFIRM", 17 | 0x00001000: "MSG_RST", 18 | 0x00002000: "MSG_ERRQUEUE", 19 | 0x00004000: "MSG_NOSIGNAL", 20 | 0x00008000: "MSG_MORE", 21 | 0x00010000: "MSG_WAITFORONE", 22 | 0x00020000: "MSG_SENDPAGE_NOTLAST", 23 | 0x20000000: "MSG_FASTOPEN", 24 | 0x40000000: "MSG_CMSG_CLOEXEC", 25 | 0x80000000: "MSG_CMSG_COMPAT", 26 | } 27 | -------------------------------------------------------------------------------- /headers/rlimit_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/uapi/asm-generic/resource.h 4 | var RlimitLookup = map[int]string{ 5 | 0: "RLIMIT_CPU", 6 | 1: "RLIMIT_FSIZE", 7 | 2: "RLIMIT_DATA", 8 | 3: "RLIMIT_STACK", 9 | 4: "RLIMIT_CORE", 10 | 5: "RLIMIT_RSS", 11 | 6: "RLIMIT_NPROC", 12 | 7: "RLIMIT_NOFILE", 13 | 8: "RLIMIT_MEMLOCK", 14 | 9: "RLIMIT_AS", 15 | 10: "RLIMIT_LOCKS", 16 | 11: "RLIMIT_SIGPENDING", 17 | 12: "RLIMIT_MSGQUEUE", 18 | 13: "RLIMIT_NICE", 19 | 14: "RLIMIT_RTPRIO", 20 | 15: "RLIMIT_RTTIME", 21 | } 22 | -------------------------------------------------------------------------------- /headers/sched_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/uapi/linux/sched.h 4 | 5 | var SchedLookup = map[int]string{ 6 | 0: "SCHED_OTHER", 7 | 1: "SCHED_FIFO", 8 | 2: "SCHED_RR", 9 | 3: "SCHED_BATCH", 10 | 5: "SCHED_IDLE", 11 | 6: "SCHED_DEADLINE", 12 | } 13 | -------------------------------------------------------------------------------- /headers/seccomp_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/uapi/linux/seccomp.h 4 | var SeccompCodeLookUp = map[int]string{ 5 | 0x00000000: "kill", 6 | 0x00030000: "trap", 7 | 0x00050000: "errno", 8 | 0x7ff00000: "trace", 9 | 0x7fff0000: "allow", 10 | } 11 | -------------------------------------------------------------------------------- /headers/seek_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/uapi/linux/fs.h 4 | var SeekLookup = map[int]string{ 5 | 0: "SEEK_SET", 6 | 1: "SEEK_CUR", 7 | 2: "SEEK_END", 8 | 3: "SEEK_DATA", 9 | 4: "SEEK_HOLE", 10 | } 11 | -------------------------------------------------------------------------------- /headers/signal_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | //Location: include/uapi/asm-generic/signal.h 4 | var SignalLookup = map[int]string{ 5 | 0: "SIG0", 6 | 1: "SIGHUP", 7 | 2: "SIGINT", 8 | 3: "SIGQUIT", 9 | 4: "SIGILL", 10 | 5: "SIGTRAP", 11 | 6: "SIGABRT", 12 | 7: "SIGBUS", 13 | 8: "SIGFPE", 14 | 9: "SIGKILL", 15 | 10: "SIGUSR1", 16 | 11: "SIGSEGV", 17 | 12: "SIGUSR2", 18 | 13: "SIGPIPE", 19 | 14: "SIGALRM", 20 | 15: "SIGTERM", 21 | 16: "SIGSTKFLT", 22 | 17: "SIGCHLD", 23 | 18: "SIGCONT", 24 | 19: "SIGSTOP", 25 | 20: "SIGTSTP", 26 | 21: "SIGTTIN", 27 | 22: "SIGTTOU", 28 | 23: "SIGURG", 29 | 24: "SIGXCPU", 30 | 25: "SIGXFSZ", 31 | 26: "SIGVTALRM", 32 | 27: "SIGPROF", 33 | 28: "SIGWINCH", 34 | 29: "SIGIO", 35 | 30: "IGPWR", 36 | 31: "SIGSYS", 37 | } 38 | -------------------------------------------------------------------------------- /headers/sock_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | import "syscall" 4 | 5 | // Location: include/uapi/linux/net.h 6 | var SockLookup = map[int]string{ 7 | syscall.SYS_SOCKET: "socket", 8 | syscall.SYS_BIND: "bind", 9 | syscall.SYS_CONNECT: "connect", 10 | syscall.SYS_LISTEN: "listen", 11 | syscall.SYS_ACCEPT: "accept", 12 | syscall.SYS_GETSOCKNAME: "getsockname", 13 | syscall.SYS_GETPEERNAME: "getpeername", 14 | syscall.SYS_SOCKETPAIR: "socketpair", 15 | 9: "send", 16 | 10: "recv", 17 | syscall.SYS_SENDTO: "sendto", 18 | syscall.SYS_RECVFROM: "recvfrom", 19 | syscall.SYS_SHUTDOWN: "shutdown", 20 | syscall.SYS_SETSOCKOPT: "setsockopt", 21 | syscall.SYS_GETSOCKOPT: "getsockopt", 22 | syscall.SYS_SENDMSG: "sendmsg", 23 | syscall.SYS_RECVMSG: "recvmsg", 24 | syscall.SYS_ACCEPT4: "accept4", 25 | 19: "recvmmsg", 26 | 20: "sendmmsg", 27 | } 28 | -------------------------------------------------------------------------------- /headers/sockfam_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | import "syscall" 4 | 5 | //Location: include/linux/socket.h 6 | var SocketFamLookup = map[int]string{ 7 | syscall.AF_LOCAL: "local", 8 | syscall.AF_INET: "inet", 9 | syscall.AF_AX25: "ax25", 10 | syscall.AF_IPX: "ipx", 11 | syscall.AF_APPLETALK: "appletalk", 12 | syscall.AF_NETROM: "netrom", 13 | syscall.AF_BRIDGE: "bridge", 14 | syscall.AF_ATMPVC: "atmpvc", 15 | syscall.AF_X25: "x25", 16 | syscall.AF_INET6: "inet6", 17 | syscall.AF_ROSE: "rose", 18 | syscall.AF_DECnet: "decnet", 19 | syscall.AF_NETBEUI: "netbeui", 20 | syscall.AF_SECURITY: "security", 21 | syscall.AF_KEY: "key", 22 | syscall.AF_NETLINK: "netlink", 23 | syscall.AF_PACKET: "packet", 24 | syscall.AF_ASH: "ash", 25 | syscall.AF_ECONET: "econet", 26 | syscall.AF_ATMSVC: "atmsvc", 27 | syscall.AF_RDS: "rds", 28 | syscall.AF_SNA: "sna", 29 | syscall.AF_IRDA: "irda", 30 | syscall.AF_PPPOX: "pppox", 31 | syscall.AF_WANPIPE: "wanpipe", 32 | syscall.AF_LLC: "llc", 33 | syscall.AF_CAN: "can", 34 | syscall.AF_TIPC: "tipc", 35 | syscall.AF_BLUETOOTH: "bluetooth", 36 | syscall.AF_IUCV: "iucv", 37 | syscall.AF_RXRPC: "rxrpc", 38 | syscall.AF_ISDN: "isdn", 39 | syscall.AF_PHONET: "phonet", 40 | syscall.AF_IEEE802154: "ieee802154", 41 | 37: "caif", 42 | 38: "alg", 43 | 39: "nfc", 44 | 40: "vsock", 45 | } 46 | -------------------------------------------------------------------------------- /headers/socklevel_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/linux/socket.h 4 | var SockOptLookup = map[int]string{ 5 | 0: "SOL_IP", 6 | 6: "SOL_TCP", 7 | 17: "SOL_UDP", 8 | 41: "SOL_IPV6", 9 | 58: "SOL_ICMPV6", 10 | 132: "SOL_SCTP", 11 | 136: "SOL_UDPLITE", 12 | 255: "SOL_RAW", 13 | 256: "SOL_IPX", 14 | 257: "SOL_AX25", 15 | 258: "SOL_ATALK", 16 | 259: "SOL_NETROM", 17 | 260: "SOL_ROSE", 18 | 261: "SOL_DECNET", 19 | 263: "SOL_PACKET", 20 | 264: "SOL_ATM", 21 | 265: "SOL_AAL", 22 | 266: "SOL_IRDA", 23 | 267: "SOL_NETBEUI", 24 | 268: "SOL_LLC", 25 | 269: "SOL_DCCP", 26 | 270: "SOL_NETLINK", 27 | 271: "SOL_TIPC", 28 | 272: "SOL_RXRPC", 29 | 273: "SOL_PPPOL2TP", 30 | 274: "SOL_BLUETOOTH", 31 | 275: "SOL_PNPIPE", 32 | 276: "SOL_RDS", 33 | 277: "SOL_IUCV", 34 | 278: "SOL_CAIF", 35 | 279: "SOL_ALG", 36 | 280: "SOL_NFC", 37 | } 38 | -------------------------------------------------------------------------------- /headers/sockoptname_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // File: include/uapi/asm-generic/socket.h 4 | var SockOptNameLookup = map[int]string{ 5 | 1: "SO_DEBUG", 6 | 2: "SO_REUSEADDR", 7 | 3: "SO_TYPE", 8 | 4: "SO_ERROR", 9 | 5: "SO_DONTROUTE", 10 | 6: "SO_BROADCAST", 11 | 7: "SO_SNDBUF", 12 | 8: "SO_RCVBUF", 13 | 9: "SO_KEEPALIVE", 14 | 10: "SO_OOBINLINE", 15 | 11: "SO_NO_CHECK", 16 | 12: "SO_PRIORITY", 17 | 13: "SO_LINGER", 18 | 14: "SO_BSDCOMPAT", 19 | 15: "SO_REUSEPORT", 20 | 16: "SO_PASSCRED", 21 | 17: "SO_PEERCRED", 22 | 18: "SO_RCVLOWAT", 23 | 19: "SO_SNDLOWAT", 24 | 20: "SO_RCVTIMEO", 25 | 21: "SO_SNDTIMEO", 26 | 22: "SO_SECURITY_AUTHENTICATION", 27 | 23: "SO_SECURITY_ENCRYPTION_TRANSPORT", 28 | 24: "SO_SECURITY_ENCRYPTION_NETWORK", 29 | 25: "SO_BINDTODEVICE", 30 | 26: "SO_ATTACH_FILTER", 31 | 27: "SO_DETACH_FILTER", 32 | 28: "SO_PEERNAME", 33 | 29: "SO_TIMESTAMP", 34 | 30: "SO_ACCEPTCONN", 35 | 31: "SO_PEERSEC", 36 | 32: "SO_SNDBUFFORCE", 37 | 33: "SO_RCVBUFFORCE", 38 | 34: "SO_PASSSEC", 39 | 35: "SO_TIMESTAMPNS", 40 | 36: "SO_MARK", 41 | 37: "SO_TIMESTAMPING", 42 | 38: "SO_PROTOCOL", 43 | 39: "SO_DOMAIN", 44 | 40: "SO_RXQ_OVFL", 45 | 41: "SO_WIFI_STATUS", 46 | 42: "SO_PEEK_OFF", 47 | 43: "SO_NOFCS", 48 | 44: "SO_LOCK_FILTER", 49 | 45: "SO_SELECT_ERR_QUEUE", 50 | 46: "SO_BUSY_POLL", 51 | 47: "SO_MAX_PACING_RATE", 52 | 48: "SO_BPF_EXTENSIONS", 53 | 49: "SO_INCOMING_CPU", 54 | 50: "SO_ATTACH_BPF", 55 | 56 | // PPC has these different 57 | 116: "SO_RCVLOWAT", 58 | 117: "SO_SNDLOWAT", 59 | 118: "SO_RCVTIMEO", 60 | 119: "SO_SNDTIMEO", 61 | 120: "SO_PASSCRED", 62 | 121: "SO_PEERCRED", 63 | } 64 | -------------------------------------------------------------------------------- /headers/socktype_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/linux/net.h 4 | var SockTypeLookup = map[int]string{ 5 | 1: "SOCK_STREAM", 6 | 2: "SOCK_DGRAM", 7 | 3: "SOCK_RAW", 8 | 4: "SOCK_RDM", 9 | 5: "SOCK_SEQPACKET", 10 | 6: "SOCK_DCCP", 11 | 10: "SOCK_PACKET", 12 | } 13 | -------------------------------------------------------------------------------- /headers/tcpoptname_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/uapi/linux/tcp.h 4 | var TcpOptLookup = map[int]string{ 5 | 1: "TCP_NODELAY", 6 | 2: "TCP_MAXSEG", 7 | 3: "TCP_CORK", 8 | 4: "TCP_KEEPIDLE", 9 | 5: "TCP_KEEPINTVL", 10 | 6: "TCP_KEEPCNT", 11 | 7: "TCP_SYNCNT", 12 | 8: "TCP_LINGER2", 13 | 9: "TCP_DEFER_ACCEPT", 14 | 10: "TCP_WINDOW_CLAMP", 15 | 11: "TCP_INFO", 16 | 12: "TCP_QUICKACK", 17 | 13: "TCP_CONGESTION", 18 | 14: "TCP_MD5SIG", 19 | 15: "TCP_COOKIE_TRANSACTIONS", 20 | 16: "TCP_THIN_LINEAR_TIMEOUTS", 21 | 17: "TCP_THIN_DUPACK", 22 | 18: "TCP_USER_TIMEOUT", 23 | 19: "TCP_REPAIR", 24 | 20: "TCP_REPAIR_QUEUE", 25 | 21: "TCP_QUEUE_SEQ", 26 | 22: "TCP_REPAIR_OPTIONS", 27 | 23: "TCP_FASTOPEN", 28 | 24: "TCP_TIMESTAMP", 29 | 25: "TCP_NOTSENT_LOWAT", 30 | } 31 | -------------------------------------------------------------------------------- /headers/umount_tab.go: -------------------------------------------------------------------------------- 1 | package headers 2 | 3 | // Location: include/linux/fs.h 4 | var UmountLookUp = map[int]string{ 5 | 0x00000001: "MNT_FORCE", 6 | 0x00000002: "MNT_DETACH", 7 | 0x00000004: "MNT_EXPIRE", 8 | 0x00000008: "UMOUNT_NOFOLLOW", 9 | 0x80000001: "UMOUNT_UNUSED", 10 | } 11 | -------------------------------------------------------------------------------- /libaudit.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | // Package libaudit is a client library used for interfacing with the Linux kernel auditing framework. It 6 | // provides an API for executing audit related tasks such as setting audit rules, changing the auditing 7 | // configuration, and processing incoming audit events. 8 | // 9 | // The intent for this package is to provide a means for an application to take the role of auditd, for 10 | // consumption and analysis of audit events in your go program. 11 | package libaudit 12 | 13 | import ( 14 | "bytes" 15 | "encoding/binary" 16 | "fmt" 17 | "sync/atomic" 18 | "syscall" 19 | "unsafe" 20 | ) 21 | 22 | // The sequence number used for requests from us to the kernel in netlink messages, 23 | // just increments. 24 | var sequenceNumber uint32 25 | 26 | // hostEndian is initialized to the byte order of the system 27 | var hostEndian binary.ByteOrder 28 | 29 | func init() { 30 | hostEndian = nativeEndian() 31 | } 32 | 33 | func nextSequence() uint32 { 34 | return atomic.AddUint32(&sequenceNumber, 1) 35 | } 36 | 37 | // NetlinkMessage is the struct type that is used for communicating on netlink sockets. 38 | type NetlinkMessage syscall.NetlinkMessage 39 | 40 | // auditStatus represents the c struct audit_status (libaudit.h). It is used for passing 41 | // information related to the status of the auditing services between the kernel and 42 | // userspace. 43 | type auditStatus struct { 44 | Mask uint32 /* Bit mask for valid entries */ 45 | Enabled uint32 /* 1 = enabled, 0 = disabled */ 46 | Failure uint32 /* Failure-to-log action */ 47 | Pid uint32 /* pid of auditd process */ 48 | RateLimit uint32 /* messages rate limit (per second) */ 49 | BacklogLimit uint32 /* waiting messages limit */ 50 | Lost uint32 /* messages lost */ 51 | Backlog uint32 /* messages waiting in queue */ 52 | Version uint32 /* audit api version number */ 53 | BacklogWaitTime uint32 /* message queue wait timeout */ 54 | } 55 | 56 | // Netlink is an abstracting netlink IO functions; generally used with NetlinkConnection 57 | type Netlink interface { 58 | Send(request *NetlinkMessage) error // Send a NetlinkMessage 59 | Receive(nonblocking bool) ([]NetlinkMessage, error) // Receive netlink message(s) from the kernel 60 | GetPID() (int, error) // Get netlink peer PID 61 | } 62 | 63 | // NetlinkConnection describes a netlink interface with the kernel. 64 | // 65 | // Programs should call NewNetlinkConnection() to create a new instance. 66 | type NetlinkConnection struct { 67 | fd int // File descriptor used for communication 68 | address syscall.SockaddrNetlink // Netlink sockaddr 69 | } 70 | 71 | // Close closes the Netlink connection. 72 | func (s *NetlinkConnection) Close() { 73 | syscall.Close(s.fd) 74 | } 75 | 76 | // Send sends NetlinkMessage request using an allocated NetlinkConnection. 77 | func (s *NetlinkConnection) Send(request *NetlinkMessage) error { 78 | return syscall.Sendto(s.fd, request.ToWireFormat(), 0, &s.address) 79 | } 80 | 81 | // Receive returns any available netlink messages being sent to us by the kernel. 82 | func (s *NetlinkConnection) Receive(nonblocking bool) ([]NetlinkMessage, error) { 83 | var ( 84 | flags = 0 85 | ) 86 | if nonblocking { 87 | flags |= syscall.MSG_DONTWAIT 88 | } 89 | buf := make([]byte, MAX_AUDIT_MESSAGE_LENGTH+syscall.NLMSG_HDRLEN) 90 | nr, _, err := syscall.Recvfrom(s.fd, buf, flags) 91 | if err != nil { 92 | return nil, err 93 | } 94 | return parseAuditNetlinkMessage(buf[:nr]) 95 | } 96 | 97 | // GetPID returns the netlink port ID of the netlink socket peer. 98 | func (s *NetlinkConnection) GetPID() (int, error) { 99 | var ( 100 | address syscall.Sockaddr 101 | v *syscall.SockaddrNetlink 102 | err error 103 | ) 104 | address, err = syscall.Getsockname(s.fd) 105 | if err != nil { 106 | return 0, err 107 | } 108 | v = address.(*syscall.SockaddrNetlink) 109 | return int(v.Pid), nil 110 | } 111 | 112 | // nativeEndian determines the byte order for the system 113 | func nativeEndian() binary.ByteOrder { 114 | var x uint32 = 0x01020304 115 | if *(*byte)(unsafe.Pointer(&x)) == 0x01 { 116 | return binary.BigEndian 117 | } 118 | return binary.LittleEndian 119 | } 120 | 121 | // ToWireFormat converts a given NetlinkMessage to a byte stream suitable to be sent to 122 | // the kernel. 123 | func (rr *NetlinkMessage) ToWireFormat() []byte { 124 | buf := new(bytes.Buffer) 125 | pbytes := nlmAlignOf(int(rr.Header.Len)) - int(rr.Header.Len) 126 | err := binary.Write(buf, hostEndian, rr.Header.Len) 127 | if err != nil { 128 | return nil 129 | } 130 | err = binary.Write(buf, hostEndian, rr.Header.Type) 131 | if err != nil { 132 | return nil 133 | } 134 | err = binary.Write(buf, hostEndian, rr.Header.Flags) 135 | if err != nil { 136 | return nil 137 | } 138 | err = binary.Write(buf, hostEndian, rr.Header.Seq) 139 | if err != nil { 140 | return nil 141 | } 142 | err = binary.Write(buf, hostEndian, rr.Header.Pid) 143 | if err != nil { 144 | return nil 145 | } 146 | err = binary.Write(buf, hostEndian, rr.Data) 147 | if err != nil { 148 | return nil 149 | } 150 | if pbytes > 0 { 151 | pbuf := make([]byte, pbytes) 152 | _, err = buf.Write(pbuf) 153 | if err != nil { 154 | return nil 155 | } 156 | } 157 | return buf.Bytes() 158 | } 159 | 160 | // nlmAlignOf rounds the length of a netlink message up to align it properly. 161 | func nlmAlignOf(msglen int) int { 162 | return (msglen + syscall.NLMSG_ALIGNTO - 1) & ^(syscall.NLMSG_ALIGNTO - 1) 163 | } 164 | 165 | // parseAuditNetlinkMessage processes an incoming netlink message from the socket, 166 | // and returns a slice of NetlinkMessage types, or an error if an error is encountered. 167 | // 168 | // This function handles incoming messages with NLM_F_MULTI; in the case of 169 | // a multipart message, ret will contain all netlink messages which are part 170 | // of the kernel message. If it is not a multipart message, ret will simply 171 | // contain a single message. 172 | func parseAuditNetlinkMessage(b []byte) (ret []NetlinkMessage, err error) { 173 | for len(b) != 0 { 174 | multi := false 175 | var ( 176 | m NetlinkMessage 177 | ) 178 | 179 | m.Header.Len, b, err = netlinkPopuint32(b) 180 | if err != nil { 181 | return 182 | } 183 | // Determine our alignment size given the reported header length 184 | alignbounds := nlmAlignOf(int(m.Header.Len)) 185 | padding := alignbounds - int(m.Header.Len) 186 | 187 | // Subtract 4 from alignbounds here to account for already having popped 4 bytes 188 | // off the input buffer 189 | if len(b) < alignbounds-4 { 190 | return ret, fmt.Errorf("short read on audit message, expected %v bytes had %v", 191 | alignbounds, len(b)+4) 192 | } 193 | // If we get here, we have enough data for the entire message 194 | m.Header.Type, b, err = netlinkPopuint16(b) 195 | if err != nil { 196 | return ret, err 197 | } 198 | m.Header.Flags, b, err = netlinkPopuint16(b) 199 | if err != nil { 200 | return ret, err 201 | } 202 | if (m.Header.Flags & syscall.NLM_F_MULTI) != 0 { 203 | multi = true 204 | } 205 | m.Header.Seq, b, err = netlinkPopuint32(b) 206 | if err != nil { 207 | return ret, err 208 | } 209 | m.Header.Pid, b, err = netlinkPopuint32(b) 210 | if err != nil { 211 | return ret, err 212 | } 213 | // Determine how much data we want to read here; if this isn't NLM_F_MULTI, we'd 214 | // typically want to read m.Header.Len bytes (the length of the payload indicated in 215 | // the netlink header. 216 | // 217 | // However, this isn't always the case. Depending on what is generating the audit 218 | // message (e.g., via audit_log_end) the kernel does not include the netlink header 219 | // size in the submitted audit message. So, we just read whatever is left in the buffer 220 | // we have if this isn't multipart. 221 | // 222 | // Additionally, it seems like there are also a few messages types where the netlink paylaod 223 | // value is inaccurate and can't be relied upon. 224 | // 225 | // XXX Just consuming the rest of the buffer based on the event type might be a better 226 | // approach here. 227 | if !multi { 228 | m.Data = b 229 | } else { 230 | datalen := m.Header.Len - syscall.NLMSG_HDRLEN 231 | m.Data = b[:datalen] 232 | b = b[int(datalen)+padding:] 233 | } 234 | ret = append(ret, m) 235 | if !multi { 236 | break 237 | } 238 | } 239 | return ret, nil 240 | } 241 | 242 | // netlinkPopuint16 pops a uint16 off the front of b, returning the value and the new buffer 243 | func netlinkPopuint16(b []byte) (uint16, []byte, error) { 244 | if len(b) < 2 { 245 | return 0, b, fmt.Errorf("not enough bytes for uint16") 246 | } 247 | return hostEndian.Uint16(b[:2]), b[2:], nil 248 | } 249 | 250 | // netlinkPopuint32 pops a uint32 off the front of b, returning the value and the new buffer 251 | func netlinkPopuint32(b []byte) (uint32, []byte, error) { 252 | if len(b) < 4 { 253 | return 0, b, fmt.Errorf("not enough bytes for uint32") 254 | } 255 | return hostEndian.Uint32(b[:4]), b[4:], nil 256 | } 257 | 258 | // newNetlinkAuditRequest initializes the header section as preparation for sending a new 259 | // netlink message. 260 | func newNetlinkAuditRequest(proto uint16, family, sizeofData int) *NetlinkMessage { 261 | rr := &NetlinkMessage{} 262 | rr.Header.Len = uint32(syscall.NLMSG_HDRLEN + sizeofData) 263 | rr.Header.Type = proto 264 | rr.Header.Flags = syscall.NLM_F_REQUEST | syscall.NLM_F_ACK 265 | rr.Header.Seq = nextSequence() 266 | return rr 267 | } 268 | 269 | // NewNetlinkConnection creates a new netlink connection with the kernel audit subsystem 270 | // and returns a NetlinkConnection describing it. The process should ensure it has the 271 | // required privileges before calling. An error is returned if any error is encountered 272 | // creating the netlink connection. 273 | func NewNetlinkConnection() (ret *NetlinkConnection, err error) { 274 | ret = &NetlinkConnection{} 275 | ret.fd, err = syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_AUDIT) 276 | if err != nil { 277 | return 278 | } 279 | ret.address.Family = syscall.AF_NETLINK 280 | ret.address.Groups = 0 281 | ret.address.Pid = 0 // 0 for kernel space 282 | if err = syscall.Bind(ret.fd, &ret.address); err != nil { 283 | syscall.Close(ret.fd) 284 | return 285 | } 286 | return 287 | } 288 | 289 | // auditGetReply gets a reply to a message from the kernel. The message(s) we are looking for are 290 | // indicated by passing sequence number seq. 291 | // 292 | // Once we recieve the full response any matching messages are returned. Note this function 293 | // would generally be used to retrieve a response from various AUDIT_SET functions or similar 294 | // configuration routines, and we do not use this for draining the audit event queue. 295 | // 296 | // chkAck should be set to true if the response we are expecting is just an ACK packet back 297 | // from netlink. If chkAck is false, the function will also retrieve other types of messages 298 | // related to the specified sequence number (like the response messages related to a query). 299 | // 300 | // XXX Right now we just discard any unrelated messages, which is not neccesarily 301 | // ideal. This could be adapted to handle this better. 302 | // 303 | // XXX This function also waits until it gets the correct message, so if for some reason 304 | // the message does not come through it will not return. This should also be improved. 305 | func auditGetReply(s Netlink, seq uint32, chkAck bool) (ret []NetlinkMessage, err error) { 306 | done: 307 | for { 308 | dbrk := false 309 | msgs, err := s.Receive(false) 310 | if err != nil { 311 | return ret, err 312 | } 313 | for _, m := range msgs { 314 | socketPID, err := s.GetPID() 315 | if err != nil { 316 | return ret, err 317 | } 318 | if m.Header.Seq != seq { 319 | // Wasn't the sequence number we are looking for, just discard it 320 | continue 321 | } 322 | if int(m.Header.Pid) != socketPID { 323 | // PID didn't match, just discard it 324 | continue 325 | } 326 | if m.Header.Type == syscall.NLMSG_DONE { 327 | break done 328 | } 329 | if m.Header.Type == syscall.NLMSG_ERROR { 330 | e := int32(hostEndian.Uint32(m.Data[0:4])) 331 | if e == 0 { 332 | // ACK response from the kernel; if chkAck is true 333 | // we just return as there is nothing left to do 334 | if chkAck { 335 | break done 336 | } 337 | // Otherwise, keep going so we can get the response 338 | // we want 339 | continue 340 | } else { 341 | return ret, fmt.Errorf("error while recieving reply %v", e) 342 | } 343 | } 344 | ret = append(ret, m) 345 | if (m.Header.Flags & syscall.NLM_F_MULTI) == 0 { 346 | // If it's not a multipart message, once we get one valid 347 | // message just return 348 | dbrk = true 349 | break 350 | } 351 | } 352 | if dbrk { 353 | break 354 | } 355 | } 356 | return ret, nil 357 | } 358 | 359 | // auditSendStatus sends AUDIT_SET with the associated auditStatus configuration 360 | func auditSendStatus(s Netlink, status auditStatus) (err error) { 361 | buf := new(bytes.Buffer) 362 | err = binary.Write(buf, hostEndian, status) 363 | if err != nil { 364 | return 365 | } 366 | wb := newNetlinkAuditRequest(uint16(AUDIT_SET), syscall.AF_NETLINK, AUDIT_STATUS_SIZE) 367 | wb.Data = buf.Bytes() 368 | if err = s.Send(wb); err != nil { 369 | return 370 | } 371 | _, err = auditGetReply(s, wb.Header.Seq, true) 372 | if err != nil { 373 | return 374 | } 375 | return nil 376 | } 377 | 378 | // AuditSetEnabled enables or disables auditing in the kernel. 379 | func AuditSetEnabled(s Netlink, enabled bool) (err error) { 380 | var status auditStatus 381 | if enabled { 382 | status.Enabled = 1 383 | } else { 384 | status.Enabled = 0 385 | } 386 | status.Mask = AUDIT_STATUS_ENABLED 387 | return auditSendStatus(s, status) 388 | } 389 | 390 | // AuditIsEnabled returns true if auditing is enabled in the kernel. 391 | func AuditIsEnabled(s Netlink) (bool, error) { 392 | var status auditStatus 393 | 394 | wb := newNetlinkAuditRequest(uint16(AUDIT_GET), syscall.AF_NETLINK, 0) 395 | if err := s.Send(wb); err != nil { 396 | return false, err 397 | } 398 | 399 | msgs, err := auditGetReply(s, wb.Header.Seq, false) 400 | if err != nil { 401 | return false, err 402 | } 403 | if len(msgs) != 1 { 404 | return false, fmt.Errorf("unexpected number of responses from kernel for status request") 405 | } 406 | m := msgs[0] 407 | if m.Header.Type != uint16(AUDIT_GET) { 408 | return false, fmt.Errorf("status request response type was invalid") 409 | } 410 | // Convert the response to auditStatus 411 | buf := bytes.NewBuffer(m.Data) 412 | err = binary.Read(buf, hostEndian, &status) 413 | if err != nil { 414 | return false, err 415 | } 416 | if status.Enabled == 1 { 417 | return true, nil 418 | } 419 | return false, nil 420 | } 421 | 422 | // AuditSetPID sets the PID for the audit daemon in the kernel (audit_set_pid(3)) 423 | func AuditSetPID(s Netlink, pid int) error { 424 | var status auditStatus 425 | status.Mask = AUDIT_STATUS_PID 426 | status.Pid = uint32(pid) 427 | return auditSendStatus(s, status) 428 | } 429 | 430 | // AuditSetRateLimit sets the rate limit for audit messages from the kernel 431 | func AuditSetRateLimit(s Netlink, limit int) error { 432 | var status auditStatus 433 | status.Mask = AUDIT_STATUS_RATE_LIMIT 434 | status.RateLimit = uint32(limit) 435 | return auditSendStatus(s, status) 436 | } 437 | 438 | // AuditSetBacklogLimit sets the backlog limit for audit messages in the kernel 439 | func AuditSetBacklogLimit(s Netlink, limit int) error { 440 | var status auditStatus 441 | status.Mask = AUDIT_STATUS_BACKLOG_LIMIT 442 | status.BacklogLimit = uint32(limit) 443 | return auditSendStatus(s, status) 444 | } 445 | -------------------------------------------------------------------------------- /libaudit_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package libaudit 6 | 7 | import ( 8 | "bufio" 9 | "bytes" 10 | "math/rand" 11 | "os" 12 | "os/exec" 13 | "strconv" 14 | "strings" 15 | "syscall" 16 | "testing" 17 | "time" 18 | ) 19 | 20 | func TestWireFormat(t *testing.T) { 21 | rr := NetlinkMessage{} 22 | rr.Header.Len = uint32(syscall.NLMSG_HDRLEN + 4) 23 | rr.Header.Type = syscall.AF_NETLINK 24 | rr.Header.Flags = syscall.NLM_F_REQUEST | syscall.NLM_F_ACK 25 | rr.Header.Seq = 2 26 | 27 | data := make([]byte, 4) 28 | hostEndian.PutUint32(data, 12) 29 | rr.Data = append(rr.Data[:], data[:]...) 30 | 31 | expected := []byte{20, 0, 0, 0, 16, 0, 5, 0, 2, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0} 32 | result := rr.ToWireFormat() 33 | if bytes.Compare(expected, result) != 0 { 34 | t.Fatalf("ToWireFormat: resulting bytes unexpected") 35 | } 36 | } 37 | 38 | func TestNetlinkConnection(t *testing.T) { 39 | if os.Getuid() != 0 { 40 | t.Skipf("skipping test, not root user") 41 | } 42 | s, err := NewNetlinkConnection() 43 | if err != nil { 44 | t.Fatalf("NewNetlinkConnection: %v", err) 45 | } 46 | defer s.Close() 47 | wb := newNetlinkAuditRequest(uint16(AUDIT_GET), syscall.AF_NETLINK, 0) 48 | if err = s.Send(wb); err != nil { 49 | t.Errorf("Send: %v", err) 50 | } 51 | _, err = auditGetReply(s, wb.Header.Seq, true) 52 | if err != nil { 53 | t.Errorf("TestNetlinkConnection: test failed %v", err) 54 | } 55 | } 56 | 57 | func TestSetters(t *testing.T) { 58 | rand.Seed(time.Now().Unix()) 59 | var ( 60 | s *NetlinkConnection 61 | pid = os.Getpid() 62 | ratelimit = 20 + rand.Intn(480) 63 | backlog = 20 + rand.Intn(480) 64 | ) 65 | if os.Getuid() != 0 { 66 | t.Skipf("skipping test, not root user") 67 | } 68 | s, err := NewNetlinkConnection() 69 | if err != nil { 70 | t.Fatalf("NewNetlinkConnection: %v", err) 71 | } 72 | defer s.Close() 73 | err = AuditSetEnabled(s, true) 74 | if err != nil { 75 | t.Fatalf("AuditSetEnabled: %v", err) 76 | } 77 | auditstatus, err := AuditIsEnabled(s) 78 | if err != nil { 79 | t.Fatalf("AuditIsEnabled: %v", err) 80 | } 81 | if !auditstatus { 82 | t.Fatalf("AuditIsEnabled returned false") 83 | } 84 | err = AuditSetRateLimit(s, ratelimit) 85 | if err != nil { 86 | t.Fatalf("AuditSetRateLimit: %v", err) 87 | } 88 | err = AuditSetBacklogLimit(s, backlog) 89 | if err != nil { 90 | t.Fatalf("AuditSetBacklogLimit: %v", err) 91 | } 92 | err = AuditSetPID(s, pid) 93 | if err != nil { 94 | t.Fatalf("AuditSetPID: %v", err) 95 | } 96 | 97 | // Use the external auditctl program to obtain the set values, and compare to what we 98 | // expect 99 | cmd := exec.Command("auditctl", "-s") 100 | cmdOutput := &bytes.Buffer{} 101 | cmd.Stdout = cmdOutput 102 | if err := cmd.Run(); err != nil { 103 | t.Fatalf("exec auditctl: %v", err) 104 | } 105 | 106 | scanner := bufio.NewScanner(cmdOutput) 107 | for scanner.Scan() { 108 | args := strings.Split(scanner.Text(), " ") 109 | if len(args) < 2 { 110 | t.Fatalf("auditctl: malformed output %q", scanner.Text()) 111 | } 112 | switch args[0] { 113 | case "enabled": 114 | if args[1] != "1" { 115 | t.Fatalf("enabled should have been 1") 116 | } 117 | case "pid": 118 | v, err := strconv.Atoi(args[1]) 119 | if err != nil { 120 | t.Fatalf("pid argument was not an integer") 121 | } 122 | if v != pid { 123 | t.Fatalf("pid should have been %v, was %v", pid, v) 124 | } 125 | case "rate_limit": 126 | v, err := strconv.Atoi(args[1]) 127 | if err != nil { 128 | t.Fatalf("rate_limit argument was not an integer") 129 | } 130 | if v != ratelimit { 131 | t.Fatalf("ratelimit should have been %v, was %v", ratelimit, v) 132 | } 133 | case "backlog_limit": 134 | v, err := strconv.Atoi(args[1]) 135 | if err != nil { 136 | t.Fatalf("backlog_limit argument was not an integer") 137 | } 138 | if v != backlog { 139 | t.Fatalf("backlog_limit should have been %v, was %v", backlog, v) 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /lookup_tables.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package libaudit 6 | 7 | // fieldLookupMap is for interpreting field names in audit messages for their integer values 8 | var fieldLookupMap = map[string]fieldType{ 9 | "auid": typeUID, 10 | "uid": typeUID, 11 | "euid": typeUID, 12 | "suid": typeUID, 13 | "fsuid": typeUID, 14 | "ouid": typeUID, 15 | "oauid": typeUID, 16 | "iuid": typeUID, 17 | "id": typeUID, 18 | "inode_uid": typeUID, 19 | "sauid": typeUID, 20 | "obj_uid": typeUID, 21 | "obj_gid": typeGID, 22 | "gid": typeGID, 23 | "egid": typeGID, 24 | "sgid": typeGID, 25 | "fsgid": typeGID, 26 | "ogid": typeGID, 27 | "igid": typeGID, 28 | "inode_gid": typeGID, 29 | "new_gid": typeGID, 30 | "syscall": typeSyscall, 31 | "arch": typeArch, 32 | "exit": typeExit, 33 | "path": typeEscaped, 34 | "comm": typeEscaped, 35 | "exe": typeEscaped, 36 | "file": typeEscaped, 37 | "name": typeEscaped, 38 | "watch": typeEscaped, 39 | "cwd": typeEscaped, 40 | "cmd": typeEscaped, 41 | "acct": typeEscaped, 42 | "dir": typeEscaped, 43 | "key": typeEscaped, 44 | "vm": typeEscaped, 45 | "old-disk": typeEscaped, 46 | "new-disk": typeEscaped, 47 | "old-fs": typeEscaped, 48 | "new-fs": typeEscaped, 49 | "device": typeEscaped, 50 | "cgroup": typeEscaped, 51 | "perm": typePerm, 52 | "perm_mask": typePerm, 53 | "mode": typeMode, 54 | "saddr": typeSockaddr, 55 | "prom": typePromisc, 56 | "old_prom": typePromisc, 57 | "capability": typeCapability, 58 | "res": typeSuccess, 59 | "result": typeSuccess, 60 | "a0": typeA0, 61 | "a1": typeA1, 62 | "a2": typeA2, 63 | "a3": typeA3, 64 | "sig": typeSignal, 65 | "list": typeList, 66 | "data": typeTTYData, 67 | "ses": typeSession, 68 | "cap_pi": typeCapBitmap, 69 | "cap_pe": typeCapBitmap, 70 | "cap_pp": typeCapBitmap, 71 | "cap_fi": typeCapBitmap, 72 | "cap_fp": typeCapBitmap, 73 | "fp": typeCapBitmap, 74 | "fi": typeCapBitmap, 75 | "fe": typeCapBitmap, 76 | "old_pp": typeCapBitmap, 77 | "old_pi": typeCapBitmap, 78 | "old_pe": typeCapBitmap, 79 | "new_pp": typeCapBitmap, 80 | "new_pi": typeCapBitmap, 81 | "new_pe": typeCapBitmap, 82 | "family": typeNFProto, 83 | "icmptype": typeICMP, 84 | "proto": typeProtocol, 85 | "addr": typeAddr, 86 | "apparmor": typeEscaped, 87 | "operation": typeEscaped, 88 | "denied_mask": typeEscaped, 89 | "info": typeEscaped, 90 | "profile": typeEscaped, 91 | "requested_mask": typeEscaped, 92 | "per": typePersonality, 93 | "code": typeSeccomp, 94 | "old-rng": typeEscaped, 95 | "new-rng": typeEscaped, 96 | "oflag": typeOFlag, 97 | "ocomm": typeEscaped, 98 | "flags": typeMmap, 99 | "sigev_signo": typeEscaped, 100 | "subj": typeMacLabel, 101 | "obj": typeMacLabel, 102 | "scontext": typeMacLabel, 103 | "tcontext": typeMacLabel, 104 | "vm-ctx": typeMacLabel, 105 | "img-ctx": typeMacLabel, 106 | "proctitle": typeProctile, 107 | "grp": typeEscaped, 108 | "new_group": typeEscaped, 109 | } 110 | 111 | // actionLookup is for mapping audit actions applied on auditRuleData 112 | var actionLookup = map[int]string{ 113 | AUDIT_NEVER: "never", 114 | AUDIT_POSSIBLE: "possible", 115 | AUDIT_ALWAYS: "always", 116 | } 117 | 118 | // flagLookup is for mapping flags applied on auditRuleData 119 | var flagLookup = map[int]string{ 120 | AUDIT_FILTER_TASK: "task", 121 | AUDIT_FILTER_ENTRY: "entry", 122 | AUDIT_FILTER_EXIT: "exit", 123 | AUDIT_FILTER_USER: "user", 124 | AUDIT_FILTER_EXCLUDE: "exclude", 125 | } 126 | 127 | // opLookup is for mapping operators applied on auditRuleData 128 | var opLookup = map[int]string{ 129 | AUDIT_EQUAL: "=", 130 | AUDIT_NOT_EQUAL: "!=", 131 | AUDIT_GREATER_THAN: ">", 132 | AUDIT_GREATER_THAN_OR_EQUAL: ">=", 133 | AUDIT_LESS_THAN: "<", 134 | AUDIT_LESS_THAN_OR_EQUAL: "<=", 135 | AUDIT_BIT_MASK: "&", 136 | AUDIT_BIT_TEST: "&=", 137 | } 138 | 139 | // fieldLookup is for mapping fields applied on auditRuleData and also used for interpreting 140 | // fields set in auditRuleData struct 141 | var fieldLookup = map[int]string{ 142 | AUDIT_PID: "pid", 143 | AUDIT_UID: "uid", 144 | AUDIT_EUID: "euid", 145 | AUDIT_SUID: "suid", 146 | AUDIT_FSUID: "fsuid", 147 | AUDIT_GID: "gid", 148 | AUDIT_EGID: "egid", 149 | AUDIT_SGID: "sgid", 150 | AUDIT_FSGID: "fsgid", 151 | AUDIT_LOGINUID: "auid", 152 | // AUDIT_LOGINUID: "loginuid", 153 | AUDIT_PERS: "pers", 154 | AUDIT_ARCH: "arch", 155 | AUDIT_MSGTYPE: "msgtype", 156 | AUDIT_SUBJ_USER: "subj_user", 157 | AUDIT_SUBJ_ROLE: "subj_role", 158 | AUDIT_SUBJ_TYPE: "subj_type", 159 | AUDIT_SUBJ_SEN: "subj_sen", 160 | AUDIT_SUBJ_CLR: "subj_clr", 161 | AUDIT_PPID: "ppid", 162 | AUDIT_OBJ_USER: "obj_user", 163 | AUDIT_OBJ_ROLE: "obj_role", 164 | AUDIT_OBJ_TYPE: "obj_type", 165 | AUDIT_OBJ_LEV_LOW: "obj_lev_low", 166 | AUDIT_OBJ_LEV_HIGH: "obj_lev_high", 167 | AUDIT_DEVMAJOR: "devmajor", 168 | AUDIT_DEVMINOR: "devminor", 169 | AUDIT_INODE: "inode", 170 | AUDIT_EXIT: "exit", 171 | AUDIT_SUCCESS: "success", 172 | AUDIT_WATCH: "path", 173 | AUDIT_PERM: "perm", 174 | AUDIT_DIR: "dir", 175 | AUDIT_FILETYPE: "filetype", 176 | AUDIT_OBJ_UID: "obj_uid", 177 | AUDIT_OBJ_GID: "obj_gid", 178 | AUDIT_FIELD_COMPARE: "field_compare", 179 | AUDIT_ARG0: "a0", 180 | AUDIT_ARG1: "a1", 181 | AUDIT_ARG2: "a2", 182 | AUDIT_ARG3: "a3", 183 | AUDIT_FILTERKEY: "key", 184 | AUDIT_EXE: "exe", 185 | } 186 | 187 | // msgTypeTab is to look up audit header type based on string prefixes attached to audit messages 188 | var msgTypeTab = map[string]auditConstant{ 189 | "USER": AUDIT_USER, 190 | "LOGIN": AUDIT_LOGIN, 191 | "USER_AUTH": AUDIT_USER_AUTH, 192 | "USER_ACCT": AUDIT_USER_ACCT, 193 | "USER_MGMT": AUDIT_USER_MGMT, 194 | "CRED_ACQ": AUDIT_CRED_ACQ, 195 | "CRED_DISP": AUDIT_CRED_DISP, 196 | "USER_START": AUDIT_USER_START, 197 | "USER_END": AUDIT_USER_END, 198 | "USER_AVC": AUDIT_USER_AVC, 199 | "USER_CHAUTHTOK": AUDIT_USER_CHAUTHTOK, 200 | "USER_ERR": AUDIT_USER_ERR, 201 | "CRED_REFR": AUDIT_CRED_REFR, 202 | "USYS_CONFIG": AUDIT_USYS_CONFIG, 203 | "USER_LOGIN": AUDIT_USER_LOGIN, 204 | "USER_LOGOUT": AUDIT_USER_LOGOUT, 205 | "ADD_USER": AUDIT_ADD_USER, 206 | "DEL_USER": AUDIT_DEL_USER, 207 | "ADD_GROUP": AUDIT_ADD_GROUP, 208 | "DEL_GROUP": AUDIT_DEL_GROUP, 209 | "DAC_CHECK": AUDIT_DAC_CHECK, 210 | "CHGRP_ID": AUDIT_CHGRP_ID, 211 | "TEST": AUDIT_TEST, 212 | "TRUSTED_APP": AUDIT_TRUSTED_APP, 213 | "USER_SELINUX_ERR": AUDIT_USER_SELINUX_ERR, 214 | "USER_CMD": AUDIT_USER_CMD, 215 | "USER_TTY": AUDIT_USER_TTY, 216 | "CHUSER_ID": AUDIT_CHUSER_ID, 217 | "GRP_AUTH": AUDIT_GRP_AUTH, 218 | "MAC_CHECK": AUDIT_MAC_CHECK, 219 | "ACCT_LOCK": AUDIT_ACCT_LOCK, 220 | "ACCT_UNLOCK": AUDIT_ACCT_UNLOCK, 221 | "SYSTEM_BOOT": AUDIT_SYSTEM_BOOT, 222 | "SYSTEM_SHUTDOWN": AUDIT_SYSTEM_SHUTDOWN, 223 | "SYSTEM_RUNLEVEL": AUDIT_SYSTEM_RUNLEVEL, 224 | "SERVICE_START": AUDIT_SERVICE_START, 225 | "SERVICE_STOP": AUDIT_SERVICE_STOP, 226 | "GRP_MGMT": AUDIT_GRP_MGMT, 227 | "GRP_CHAUTHTOK": AUDIT_GRP_CHAUTHTOK, 228 | // "DAEMON_START": AUDIT_DAEMON_START, 229 | // "DAEMON_END": AUDIT_DAEMON_END, 230 | // "DAEMON_ABORT": AUDIT_DAEMON_ABORT, 231 | "DAEMON_CONFIG": AUDIT_DAEMON_CONFIG, 232 | "DAEMON_RECONFIG": AUDIT_DAEMON_RECONFIG, 233 | "DAEMON_ROTATE": AUDIT_DAEMON_ROTATE, 234 | "DAEMON_RESUME": AUDIT_DAEMON_RESUME, 235 | "DAEMON_ACCEPT": AUDIT_DAEMON_ACCEPT, 236 | "DAEMON_CLOSE": AUDIT_DAEMON_CLOSE, 237 | // "DAEMON_ERR": AUDIT_DAEMON_ERR, 238 | "SYSCALL": AUDIT_SYSCALL, 239 | // "FS_WATCH": AUDIT_FS_WATCH, 240 | "PATH": AUDIT_PATH, 241 | "IPC": AUDIT_IPC, 242 | "SOCKETCALL": AUDIT_SOCKETCALL, 243 | "CONFIG_CHANGE": AUDIT_CONFIG_CHANGE, 244 | "SOCKADDR": AUDIT_SOCKADDR, 245 | "CWD": AUDIT_CWD, 246 | // "FS_INODE": AUDIT_FS_INODE, 247 | "EXECVE": AUDIT_EXECVE, 248 | "IPC_SET_PERM": AUDIT_IPC_SET_PERM, 249 | "MQ_OPEN": AUDIT_MQ_OPEN, 250 | "MQ_SENDRECV": AUDIT_MQ_SENDRECV, 251 | "MQ_NOTIFY": AUDIT_MQ_NOTIFY, 252 | "MQ_GETSETATTR": AUDIT_MQ_GETSETATTR, 253 | "KERNEL_OTHER": AUDIT_KERNEL_OTHER, 254 | "FD_PAIR": AUDIT_FD_PAIR, 255 | "OBJ_PID": AUDIT_OBJ_PID, 256 | "TTY": AUDIT_TTY, 257 | "EOE": AUDIT_EOE, 258 | "BPRM_FCAPS": AUDIT_BPRM_FCAPS, 259 | "CAPSET": AUDIT_CAPSET, 260 | "MMAP": AUDIT_MMAP, 261 | "NETFILTER_PKT": AUDIT_NETFILTER_PKT, 262 | "NETFILTER_CFG": AUDIT_NETFILTER_CFG, 263 | "SECCOMP": AUDIT_SECCOMP, 264 | "PROCTITLE": AUDIT_PROCTITLE, 265 | "FEATURE_CHANGE": AUDIT_FEATURE_CHANGE, 266 | "AVC": AUDIT_AVC, 267 | "SELINUX_ERR": AUDIT_SELINUX_ERR, 268 | "AVC_PATH": AUDIT_AVC_PATH, 269 | "MAC_POLICY_LOAD": AUDIT_MAC_POLICY_LOAD, 270 | "MAC_STATUS": AUDIT_MAC_STATUS, 271 | "MAC_CONFIG_CHANGE": AUDIT_MAC_CONFIG_CHANGE, 272 | "MAC_UNLBL_ALLOW": AUDIT_MAC_UNLBL_ALLOW, 273 | "MAC_CIPSOV4_ADD": AUDIT_MAC_CIPSOV4_ADD, 274 | "MAC_CIPSOV4_DEL": AUDIT_MAC_CIPSOV4_DEL, 275 | "MAC_MAP_ADD": AUDIT_MAC_MAP_ADD, 276 | "MAC_MAP_DEL": AUDIT_MAC_MAP_DEL, 277 | "MAC_IPSEC_ADDSA": AUDIT_MAC_IPSEC_ADDSA, 278 | "MAC_IPSEC_DELSA": AUDIT_MAC_IPSEC_DELSA, 279 | "MAC_IPSEC_ADDSPD": AUDIT_MAC_IPSEC_ADDSPD, 280 | "MAC_IPSEC_DELSPD": AUDIT_MAC_IPSEC_DELSPD, 281 | "MAC_IPSEC_EVENT": AUDIT_MAC_IPSEC_EVENT, 282 | "MAC_UNLBL_STCADD": AUDIT_MAC_UNLBL_STCADD, 283 | "MAC_UNLBL_STCDEL": AUDIT_MAC_UNLBL_STCDEL, 284 | "ANOM_PROMISCUOUS": AUDIT_ANOM_PROMISCUOUS, 285 | "ANOM_ABEND": AUDIT_ANOM_ABEND, 286 | "ANOM_LINK": AUDIT_ANOM_LINK, 287 | "INTEGRITY_DATA": AUDIT_INTEGRITY_DATA, 288 | "INTEGRITY_METADATA": AUDIT_INTEGRITY_METADATA, 289 | "INTEGRITY_STATUS": AUDIT_INTEGRITY_STATUS, 290 | "INTEGRITY_HASH": AUDIT_INTEGRITY_HASH, 291 | "INTEGRITY_PCR": AUDIT_INTEGRITY_PCR, 292 | "INTEGRITY_RULE": AUDIT_INTEGRITY_RULE, 293 | "APPARMOR": AUDIT_AA, 294 | "APPARMOR_AUDIT": AUDIT_APPARMOR_AUDIT, 295 | "APPARMOR_ALLOWED": AUDIT_APPARMOR_ALLOWED, 296 | "APPARMOR_DENIED": AUDIT_APPARMOR_DENIED, 297 | // "APPARMOR_HINT": AUDIT_APPARMOR_HINT, 298 | "APPARMOR_STATUS": AUDIT_APPARMOR_STATUS, 299 | "APPARMOR_ERROR": AUDIT_APPARMOR_ERROR, 300 | "KERNEL": AUDIT_KERNEL, 301 | "ANOM_LOGIN_FAILURES": AUDIT_ANOM_LOGIN_FAILURES, 302 | "ANOM_LOGIN_TIME": AUDIT_ANOM_LOGIN_TIME, 303 | "ANOM_LOGIN_SESSIONS": AUDIT_ANOM_LOGIN_SESSIONS, 304 | "ANOM_LOGIN_ACCT": AUDIT_ANOM_LOGIN_ACCT, 305 | "ANOM_LOGIN_LOCATION": AUDIT_ANOM_LOGIN_LOCATION, 306 | "ANOM_MAX_DAC": AUDIT_ANOM_MAX_DAC, 307 | "ANOM_MAX_MAC": AUDIT_ANOM_MAX_MAC, 308 | "ANOM_AMTU_FAIL": AUDIT_ANOM_AMTU_FAIL, 309 | "ANOM_RBAC_FAIL": AUDIT_ANOM_RBAC_FAIL, 310 | "ANOM_RBAC_INTEGRITY_FAIL": AUDIT_ANOM_RBAC_INTEGRITY_FAIL, 311 | "ANOM_CRYPTO_FAIL": AUDIT_ANOM_CRYPTO_FAIL, 312 | "ANOM_ACCESS_FS": AUDIT_ANOM_ACCESS_FS, 313 | "ANOM_EXEC": AUDIT_ANOM_EXEC, 314 | "ANOM_MK_EXEC": AUDIT_ANOM_MK_EXEC, 315 | "ANOM_ADD_ACCT": AUDIT_ANOM_ADD_ACCT, 316 | "ANOM_DEL_ACCT": AUDIT_ANOM_DEL_ACCT, 317 | "ANOM_MOD_ACCT": AUDIT_ANOM_MOD_ACCT, 318 | "ANOM_ROOT_TRANS": AUDIT_ANOM_ROOT_TRANS, 319 | "RESP_ANOMALY": AUDIT_RESP_ANOMALY, 320 | "RESP_ALERT": AUDIT_RESP_ALERT, 321 | "RESP_KILL_PROC": AUDIT_RESP_KILL_PROC, 322 | "RESP_TERM_ACCESS": AUDIT_RESP_TERM_ACCESS, 323 | "RESP_ACCT_REMOTE": AUDIT_RESP_ACCT_REMOTE, 324 | "RESP_ACCT_LOCK_TIMED": AUDIT_RESP_ACCT_LOCK_TIMED, 325 | "RESP_ACCT_UNLOCK_TIMED": AUDIT_RESP_ACCT_UNLOCK_TIMED, 326 | "RESP_ACCT_LOCK": AUDIT_RESP_ACCT_LOCK, 327 | "RESP_TERM_LOCK": AUDIT_RESP_TERM_LOCK, 328 | "RESP_SEBOOL": AUDIT_RESP_SEBOOL, 329 | "RESP_EXEC": AUDIT_RESP_EXEC, 330 | "RESP_SINGLE": AUDIT_RESP_SINGLE, 331 | "RESP_HALT": AUDIT_RESP_HALT, 332 | "USER_ROLE_CHANGE": AUDIT_USER_ROLE_CHANGE, 333 | "ROLE_ASSIGN": AUDIT_ROLE_ASSIGN, 334 | "ROLE_REMOVE": AUDIT_ROLE_REMOVE, 335 | "LABEL_OVERRIDE": AUDIT_LABEL_OVERRIDE, 336 | "LABEL_LEVEL_CHANGE": AUDIT_LABEL_LEVEL_CHANGE, 337 | "USER_LABELED_EXPORT": AUDIT_USER_LABELED_EXPORT, 338 | "USER_UNLABELED_EXPORT": AUDIT_USER_UNLABELED_EXPORT, 339 | "DEV_ALLOC": AUDIT_DEV_ALLOC, 340 | "DEV_DEALLOC": AUDIT_DEV_DEALLOC, 341 | "FS_RELABEL": AUDIT_FS_RELABEL, 342 | "USER_MAC_POLICY_LOAD": AUDIT_USER_MAC_POLICY_LOAD, 343 | "ROLE_MODIFY": AUDIT_ROLE_MODIFY, 344 | "USER_MAC_CONFIG_CHANGE": AUDIT_USER_MAC_CONFIG_CHANGE, 345 | "CRYPTO_TEST_USER": AUDIT_CRYPTO_TEST_USER, 346 | "CRYPTO_PARAM_CHANGE_USER": AUDIT_CRYPTO_PARAM_CHANGE_USER, 347 | "CRYPTO_LOGIN": AUDIT_CRYPTO_LOGIN, 348 | "CRYPTO_LOGOUT": AUDIT_CRYPTO_LOGOUT, 349 | "CRYPTO_KEY_USER": AUDIT_CRYPTO_KEY_USER, 350 | "CRYPTO_FAILURE_USER": AUDIT_CRYPTO_FAILURE_USER, 351 | "CRYPTO_REPLAY_USER": AUDIT_CRYPTO_REPLAY_USER, 352 | "CRYPTO_SESSION": AUDIT_CRYPTO_SESSION, 353 | "CRYPTO_IKE_SA": AUDIT_CRYPTO_IKE_SA, 354 | "CRYPTO_IPSEC_SA": AUDIT_CRYPTO_IPSEC_SA, 355 | "VIRT_CONTROL": AUDIT_VIRT_CONTROL, 356 | "VIRT_RESOURCE": AUDIT_VIRT_RESOURCE, 357 | "VIRT_MACHINE_ID": AUDIT_VIRT_MACHINE_ID, 358 | } 359 | -------------------------------------------------------------------------------- /parser.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package libaudit 6 | 7 | import ( 8 | "fmt" 9 | "strconv" 10 | "strings" 11 | ) 12 | 13 | type record struct { 14 | syscallNum string 15 | arch string 16 | a0 int 17 | a1 int 18 | } 19 | 20 | // ErrorAuditParse is an implementation of the error interface that is returned by 21 | // ParseAuditEvent. msg will contain a description of the error, and the raw audit event 22 | // which failed parsing is returned in raw for inspection by the calling program. 23 | type ErrorAuditParse struct { 24 | Msg string 25 | Raw string 26 | } 27 | 28 | // Error returns a string representation of ErrorAuditParse e 29 | func (e ErrorAuditParse) Error() string { 30 | return e.Msg 31 | } 32 | 33 | // newErrorAuditParse returns a new ErrorAuditParse type with the fields populated 34 | func newErrorAuditParse(raw string, f string, v ...interface{}) ErrorAuditParse { 35 | ret := ErrorAuditParse{ 36 | Raw: raw, 37 | Msg: fmt.Sprintf(f, v...), 38 | } 39 | return ret 40 | } 41 | 42 | // ParseAuditEvent parses an incoming audit message from kernel and returns an AuditEvent. 43 | // 44 | // msgType is supposed to come from the calling function which holds the msg header indicating header 45 | // type of the messages. It uses simple string parsing techniques and provider better performance than 46 | // the regex parser, idea taken from parse_up_record(rnode* r) in ellist.c (libauparse). 47 | func ParseAuditEvent(str string, msgType auditConstant, interpret bool) (*AuditEvent, error) { 48 | var r record 49 | var event = AuditEvent{ 50 | Raw: str, 51 | } 52 | 53 | // Create the map which will store the audit record fields for this event, note we 54 | // provide an allocation hint here based on the average number of fields we would come 55 | // across in an audit event 56 | m := make(map[string]string, 24) 57 | 58 | if strings.HasPrefix(str, "audit(") { 59 | str = str[6:] 60 | } else { 61 | return nil, newErrorAuditParse(event.Raw, "malformed, missing audit prefix") 62 | } 63 | index := strings.Index(str, ":") 64 | if index == -1 { 65 | return nil, newErrorAuditParse(event.Raw, "malformed, can't locate start of fields") 66 | } 67 | 68 | // determine timestamp 69 | timestamp := str[:index] 70 | // move further on string, skipping ':' 71 | str = str[index+1:] 72 | index = strings.Index(str, ")") 73 | if index == -1 { 74 | return nil, newErrorAuditParse(event.Raw, "malformed, can't locate end of prefix") 75 | } 76 | serial := str[:index] 77 | if strings.HasPrefix(str, serial+"): ") { 78 | str = str[index+3:] 79 | } else { 80 | return nil, newErrorAuditParse(event.Raw, "malformed, prefix termination unexpected") 81 | } 82 | 83 | var ( 84 | nBytes string 85 | orig = len(str) 86 | n int 87 | key string 88 | value string 89 | av bool 90 | ) 91 | 92 | for n < orig { 93 | getSpaceSlice(&str, &nBytes, &n) 94 | var newIndex int 95 | newIndex = strings.Index(nBytes, "=") 96 | if newIndex == -1 { 97 | // check type for special cases of AVC and USER_AVC 98 | if msgType == AUDIT_AVC || msgType == AUDIT_USER_AVC { 99 | if nBytes == "avc:" && strings.HasPrefix(str, "avc:") { 100 | // skip over 'avc:' 101 | str = str[len(nBytes)+1:] 102 | av = true 103 | continue 104 | } 105 | if av { 106 | key = "seresult" 107 | value = nBytes 108 | if interpret { 109 | var err error 110 | value, err = interpretField(key, value, msgType, r) 111 | if err != nil { 112 | return nil, newErrorAuditParse(event.Raw, "interpretField: %v", err) 113 | } 114 | } 115 | m[key] = value 116 | av = false 117 | if len(str) == len(nBytes) { 118 | break 119 | } else { 120 | str = str[len(nBytes)+1:] 121 | } 122 | continue 123 | } 124 | if strings.HasPrefix(nBytes, "{") { 125 | key = "seperms" 126 | str = str[len(nBytes)+1:] 127 | var v string 128 | getSpaceSlice(&str, &nBytes, &n) 129 | for nBytes != "}" { 130 | if len(v) != 0 { 131 | v += "," 132 | } 133 | v += nBytes 134 | str = str[len(nBytes)+1:] 135 | getSpaceSlice(&str, &nBytes, &n) 136 | } 137 | value = v 138 | if interpret { 139 | var err error 140 | value, err = interpretField(key, value, msgType, r) 141 | if err != nil { 142 | return nil, newErrorAuditParse(event.Raw, "interpretField: %v", err) 143 | } 144 | } 145 | m[key] = value 146 | fixPunctuations(&value) 147 | if len(str) == len(nBytes) { 148 | //reached the end of message 149 | break 150 | } else { 151 | str = str[len(nBytes)+1:] 152 | } 153 | continue 154 | } else { 155 | // We might get values with space, add it to prev key 156 | // skip 'for' in avc message (special case) 157 | if nBytes == "for" { 158 | str = str[len(nBytes)+1:] 159 | continue 160 | } 161 | value += " " + nBytes 162 | fixPunctuations(&value) 163 | if interpret { 164 | var err error 165 | value, err = interpretField(key, value, msgType, r) 166 | if err != nil { 167 | return nil, newErrorAuditParse(event.Raw, "interpretField: %v", err) 168 | } 169 | } 170 | m[key] = value 171 | } 172 | } else { 173 | // We might get values with space, add it to prev key 174 | value += " " + nBytes 175 | fixPunctuations(&value) 176 | if interpret { 177 | var err error 178 | value, err = interpretField(key, value, msgType, r) 179 | if err != nil { 180 | return nil, newErrorAuditParse(event.Raw, "interpretField: %v", err) 181 | } 182 | } 183 | m[key] = value 184 | } 185 | 186 | } else { 187 | key = nBytes[:newIndex] 188 | value = nBytes[newIndex+1:] 189 | // for cases like msg=' 190 | // we look again for key value pairs 191 | if strings.HasPrefix(value, "'") && key == "msg" { 192 | newIndex = strings.Index(value, "=") 193 | if newIndex == -1 { 194 | // special case USER_AVC messages, start of: msg='avc: 195 | if strings.HasPrefix(str, "msg='avc") { 196 | str = str[5:] 197 | } 198 | continue 199 | } 200 | key = value[1:newIndex] 201 | value = value[newIndex+1:] 202 | } 203 | 204 | fixPunctuations(&value) 205 | if key == "arch" { 206 | // determine machine type 207 | } 208 | if key == "a0" { 209 | val, err := strconv.ParseInt(value, 16, 64) 210 | if err != nil { 211 | r.a0 = -1 212 | } else { 213 | r.a0 = int(val) 214 | } 215 | } 216 | if key == "a1" { 217 | val, err := strconv.ParseInt(value, 16, 64) 218 | if err != nil { 219 | r.a1 = -1 220 | } else { 221 | r.a1 = int(val) 222 | } 223 | } 224 | if key == "syscall" { 225 | r.syscallNum = value 226 | } 227 | if interpret { 228 | var err error 229 | value, err = interpretField(key, value, msgType, r) 230 | if err != nil { 231 | return nil, newErrorAuditParse(event.Raw, "interpretField: %v", err) 232 | } 233 | } 234 | m[key] = value 235 | } 236 | if len(str) == len(nBytes) { 237 | // Reached the end of message 238 | break 239 | } else { 240 | str = str[len(nBytes)+1:] 241 | } 242 | 243 | } 244 | 245 | event.Timestamp = timestamp 246 | event.Serial = serial 247 | event.Data = m 248 | event.Type = msgType.String()[6:] 249 | return &event, nil 250 | 251 | } 252 | 253 | // getSpaceSlice checks the index of the next space and put the string up to that space into 254 | // the second string, total number of characters processed is updated with each call to the function 255 | func getSpaceSlice(str *string, b *string, v *int) { 256 | index := strings.Index(*str, " ") 257 | if index != -1 { 258 | if index == 0 { 259 | // Found space on the first location only, just forward on the orig 260 | // string and try again 261 | *str = (*str)[1:] 262 | getSpaceSlice(str, b, v) 263 | } else { 264 | *b = (*str)[:index] 265 | // Keep updating total characters processed 266 | *v += len(*b) 267 | } 268 | } else { 269 | *b = (*str) 270 | // Keep updating total characters processed 271 | *v += len(*b) 272 | } 273 | } 274 | 275 | func fixPunctuations(value *string) { 276 | // Remove trailing punctuation 277 | l := len(*value) 278 | if l > 0 && strings.HasSuffix(*value, "'") { 279 | *value = (*value)[:l-1] 280 | l-- 281 | } 282 | if l > 0 && strings.HasSuffix(*value, ",") { 283 | *value = (*value)[:l-1] 284 | l-- 285 | } 286 | if l > 0 && strings.HasSuffix(*value, ")") { 287 | if *value != "(none)" && *value != "(null)" { 288 | *value = (*value)[:l-1] 289 | l-- 290 | } 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /parser_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package libaudit 6 | 7 | import ( 8 | "reflect" 9 | "testing" 10 | ) 11 | 12 | var auditTests = []struct { 13 | msg string 14 | msgType auditConstant 15 | expected error 16 | match bool 17 | event AuditEvent 18 | }{ 19 | { 20 | `audit(1226874073.147:96): avc: denied { getattr } for pid=2465 comm="httpd" path="/var/www/html/file1 space" dev=dm-0 ino=284133 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:samba_share_t:s0 tclass=file`, 21 | AUDIT_AVC, 22 | nil, 23 | true, 24 | AuditEvent{ 25 | Serial: "96", 26 | Timestamp: "1226874073.147", 27 | Type: "AVC", 28 | Data: map[string]string{ 29 | "path": `"/var/www/html/file1 space"`, "dev": "dm-0", "ino": "284133", "scontext": "unconfined_u:system_r:httpd_t:s0", "tcontext": "unconfined_u:object_r:samba_share_t:s0", "pid": "2465", "seperms": "getattr", "comm": `"httpd"`, "tclass": "file", "seresult": "denied"}, 30 | }, 31 | }, 32 | { 33 | `audit(1464176620.068:1445): auid=4294967295 uid=1000 gid=1000 ses=4294967295 pid=23975 comm="chrome" exe="/opt/google/chrome/chrome" sig=0 arch=c000003e syscall=273 compat=0 ip=0x7f1da6d8b694 code=0x50000`, 34 | AUDIT_AVC, 35 | nil, 36 | true, 37 | AuditEvent{ 38 | Serial: "1445", 39 | Timestamp: "1464176620.068", 40 | Type: "AVC", 41 | Data: map[string]string{ 42 | "comm": `"chrome"`, "exe": `"/opt/google/chrome/chrome"`, "arch": "c000003e", "compat": "0", "code": "0x50000", "ses": "4294967295", "uid": "1000", "gid": "1000", "pid": "23975", "sig": "0", "syscall": "273", "ip": "0x7f1da6d8b694", "auid": "4294967295"}, 43 | }, 44 | }, 45 | {`audit(1464163771.720:20): arch=c000003e syscall=1 success=yes exit=658651 a0=6 a1=7f26862ea010 a2=a0cdb a3=0 items=0 ppid=712 pid=716 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="apparmor_parser" exe="/sbin/apparmor_parser" key=(null)`, 46 | AUDIT_AVC, 47 | nil, 48 | true, 49 | AuditEvent{ 50 | Serial: "20", 51 | Timestamp: "1464163771.720", 52 | Type: "AVC", 53 | Data: map[string]string{ 54 | "success": "yes", "a2": "a0cdb", "uid": "0", "sgid": "0", "fsgid": "0", "ses": "4294967295", "exit": "658651", "a0": "6", "ppid": "712", "suid": "0", "key": "(null)", "tty": "(none)", "comm": `"apparmor_parser"`, "arch": "c000003e", "syscall": "1", "a1": "7f26862ea010", "items": "0", "pid": "716", "fsuid": "0", "exe": `"/sbin/apparmor_parser"`, "a3": "0", "auid": "4294967295", "gid": "0", "euid": "0", "egid": "0"}, 55 | }, 56 | }, 57 | {`audit(1464093935.845:993): pid=4148 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:setcred acct="root" exe="/usr/bin/sudo" hostname=? addr=? terminal=/dev/pts/18 res=success'`, 58 | AUDIT_AVC, 59 | nil, 60 | true, 61 | AuditEvent{ 62 | Serial: "993", 63 | Timestamp: "1464093935.845", 64 | Type: "AVC", 65 | Data: map[string]string{ 66 | "op": "PAM:setcred", "acct": `"root"`, "hostname": "?", "addr": "?", "res": "success", "uid": "0", "auid": "4294967295", "exe": `"/usr/bin/sudo"`, "terminal": "/dev/pts/18", "pid": "4148", "ses": "4294967295"}, 67 | }, 68 | }, 69 | { 70 | `audit(1267534395.930:19): user pid=1169 uid=0 auid=4294967295 ses=4294967295 subj=system_u:unconfined_r:unconfined_t msg='avc: denied { read } for request=SELinux:SELinuxGetClientContext comm=X-setest resid=3c00001 restype= scontext=unconfined_u:unconfined_r:x_select_paste_t tcontext=unconfined_u:unconfined_r:unconfined_t tclass=x_resource : exe="/usr/bin/Xorg " sauid=0 hostname=? addr=? terminal=?'`, 71 | AUDIT_AVC, 72 | nil, 73 | true, 74 | AuditEvent{ 75 | Serial: "19", 76 | Timestamp: "1267534395.930", 77 | Type: "AVC", 78 | Data: map[string]string{ 79 | "": " user", "uid": "0", "subj": "system_u:unconfined_r:unconfined_t", "scontext": "unconfined_u:unconfined_r:x_select_paste_t", "ses": "4294967295", "comm": "X-setest", "sauid": "0", "addr": "?", "pid": "1169", "auid": "4294967295", "request": "SELinux:SELinuxGetClientContext", "resid": "3c00001", "restype": "", "hostname": "?", "terminal": "?", "seresult": "denied", "seperms": "read", "tcontext": "unconfined_u:unconfined_r:unconfined_t", "tclass": "x_resource :", "exe": `"/usr/bin/Xorg "`}, 80 | }, 81 | }, 82 | { 83 | `audit(1464617439.911:1421): pid=30576 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:setcred acct="root" exe="/usr/bin/sudo" hostname=? addr=? terminal=/dev/pts/18 res=success'`, 84 | AUDIT_AVC, 85 | nil, 86 | true, 87 | AuditEvent{ 88 | Serial: "1421", 89 | Timestamp: "1464617439.911", 90 | Type: "AVC", 91 | Data: map[string]string{ 92 | "pid": "30576", "auid": "4294967295", "exe": `"/usr/bin/sudo"`, "addr": "?", "terminal": "/dev/pts/18", "uid": "0", "ses": "4294967295", "op": "PAM:setcred", "acct": `"root"`, "hostname": "?", "res": "success"}, 93 | }, 94 | }, 95 | { 96 | `audit(1464617439.911:1422): pid=30576 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:session_open acct="root" exe="/usr/bin/sudo" hostname=? addr=? terminal=/dev/pts/18 res=success'`, 97 | AUDIT_AVC, 98 | nil, 99 | true, 100 | AuditEvent{ 101 | Serial: "1422", 102 | Timestamp: "1464617439.911", 103 | Type: "AVC", 104 | Data: map[string]string{ 105 | "uid": "0", "auid": "4294967295", "ses": "4294967295", "op": "PAM:session_open", "exe": `"/usr/bin/sudo"`, "addr": "?", "terminal": "/dev/pts/18", "pid": "30576", "res": "success", "hostname": "?", "acct": `"root"`}, 106 | }, 107 | }, 108 | { 109 | `audit(1464617444.219:1425): pid=30579 uid=1000 auid=4294967295 ses=4294967295 msg='cwd="/home/arun/Work/go-ground/src/github.com/arunk-s/parser" cmd=636174202F7661722F6C6F672F61756469742F61756469742E6C6F67 terminal=pts/18 res=success'`, 110 | AUDIT_AVC, 111 | nil, 112 | true, 113 | AuditEvent{ 114 | Serial: "1425", 115 | Timestamp: "1464617444.219", 116 | Type: "AVC", 117 | Data: map[string]string{ 118 | "auid": "4294967295", "ses": "4294967295", "cwd": `"/home/arun/Work/go-ground/src/github.com/arunk-s/parser"`, "cmd": "636174202F7661722F6C6F672F61756469742F61756469742E6C6F67", "terminal": "pts/18", "res": "success", "pid": "30579", "uid": "1000"}, 119 | }, 120 | }, 121 | { 122 | `audit(1464617461.107:1431): pid=30586 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:setcred acct="root" exe="/usr/bin/sudo" hostname=? addr=? terminal=/dev/pts/18 res=success'`, 123 | AUDIT_AVC, 124 | nil, 125 | true, 126 | AuditEvent{ 127 | Serial: "1431", 128 | Timestamp: "1464617461.107", 129 | Type: "AVC", 130 | Data: map[string]string{ 131 | "exe": `"/usr/bin/sudo"`, "hostname": "?", "addr": "?", "terminal": "/dev/pts/18", "res": "success", "pid": "30586", "uid": "0", "auid": "4294967295", "ses": "4294967295", "op": "PAM:setcred", "acct": `"root"`}, 132 | }, 133 | }, 134 | { 135 | `audit(1464614823.239:1290): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=NetworkManager-dispatcher comm="systemd" exe="/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'`, 136 | AUDIT_AVC, 137 | nil, 138 | true, 139 | AuditEvent{ 140 | Serial: "1290", 141 | Timestamp: "1464614823.239", 142 | Type: "AVC", 143 | Data: map[string]string{ 144 | "hostname": "?", "addr": "?", "res": "success", "auid": "4294967295", "ses": "4294967295", "unit": "NetworkManager-dispatcher", "comm": `"systemd"`, "exe": `"/lib/systemd/systemd"`, "pid": "1", "uid": "0", "terminal": "?"}, 145 | }, 146 | }, 147 | { 148 | `audit(1464614843.495:1292): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=systemd-rfkill comm="systemd" exe="/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'`, 149 | AUDIT_AVC, 150 | nil, 151 | true, 152 | AuditEvent{ 153 | Serial: "1292", 154 | Timestamp: "1464614843.495", 155 | Type: "AVC", 156 | Data: map[string]string{ 157 | "pid": "1", "auid": "4294967295", "ses": "4294967295", "unit": "systemd-rfkill", "comm": `"systemd"`, "exe": `"/lib/systemd/systemd"`, "hostname": "?", "res": "success", "uid": "0", "addr": "?", "terminal": "?"}, 158 | }, 159 | }, 160 | { 161 | `audit(1464590772.564:302): auid=4294967295 uid=1000 gid=1000 ses=4294967295 pid=5803 comm="chrome" exe="/opt/google/chrome/chrome" sig=0 arch=c000003e syscall=273 compat=0 ip=0x7f3deee65694 code=0x50000`, 162 | AUDIT_AVC, 163 | nil, 164 | true, 165 | AuditEvent{ 166 | Serial: "302", 167 | Timestamp: "1464590772.564", 168 | Type: "AVC", 169 | Data: map[string]string{ 170 | "pid": "5803", "comm": `"chrome"`, "syscall": "273", "ip": "0x7f3deee65694", "gid": "1000", "uid": "1000", "ses": "4294967295", "exe": `"/opt/google/chrome/chrome"`, "sig": "0", "arch": "c000003e", "compat": "0", "code": "0x50000", "auid": "4294967295"}, 171 | }, 172 | }, 173 | { 174 | `audit(1464505771.166:388): pid=1 uid=0 auid=4294967295 ses=4294967295'unit=NetworkManager-dispatcher comm="systemd" exe="/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'`, 175 | AUDIT_AVC, 176 | nil, 177 | true, 178 | AuditEvent{ 179 | Serial: "388", 180 | Timestamp: "1464505771.166", 181 | Type: "AVC", 182 | Data: map[string]string{ 183 | "pid": "1", "hostname": "?", "res": "success", "terminal": "?", "uid": "0", "auid": "4294967295", "ses": "4294967295'unit=NetworkManager-dispatcher", "comm": `"systemd"`, "exe": `"/lib/systemd/systemd"`, "addr": "?"}, 184 | }, 185 | }, 186 | { 187 | `audit(1464505794.710:389): auid=4294967295 uid=1000 gid=1000 ses=4294967295 pid=4075 comm="Chrome_libJingl" exe="/opt/google/chrome/chrome" sig=0 arch=c000003e syscall=273 compat=0 ip=0x7fb359e4d694 code=0x50000`, 188 | AUDIT_AVC, 189 | nil, 190 | true, 191 | AuditEvent{ 192 | Serial: "389", 193 | Timestamp: "1464505794.710", 194 | Type: "AVC", 195 | Data: map[string]string{ 196 | "auid": "4294967295", "comm": `"Chrome_libJingl"`, "sig": "0", "arch": "c000003e", "ip": "0x7fb359e4d694", "code": "0x50000", "uid": "1000", "gid": "1000", "ses": "4294967295", "pid": "4075", "exe": `"/opt/google/chrome/chrome"`, "syscall": "273", "compat": "0"}, 197 | }, 198 | }, 199 | { 200 | `audit(1464505808.342:401): auid=4294967295 uid=1000 gid=1000 ses=4294967295 pid=4076 comm="Chrome_libJingl" exe="/opt/google/chrome/chrome" sig=0 arch=c000003e syscall=273 compat=0 ip=0x7fb359e4d694 code=0x50000`, 201 | AUDIT_AVC, 202 | nil, 203 | true, 204 | AuditEvent{ 205 | Serial: "401", 206 | Timestamp: "1464505808.342", 207 | Type: "AVC", 208 | Data: map[string]string{ 209 | "pid": "4076", "comm": `"Chrome_libJingl"`, "exe": `"/opt/google/chrome/chrome"`, "sig": "0", "syscall": "273", "compat": "0", "code": "0x50000", "ses": "4294967295", "uid": "1000", "gid": "1000", "arch": "c000003e", "ip": "0x7fb359e4d694", "auid": "4294967295"}, 210 | }, 211 | }, 212 | { 213 | `audit(1464505810.566:403): auid=4294967295 uid=1000 gid=1000 ses=4294967295 pid=4078 comm="chrome" exe="/opt/google/chrome/chrome" sig=0 arch=c000003e syscall=273 compat=0 ip=0x7fb359e4d694 code=0x50000`, 214 | AUDIT_AVC, 215 | nil, 216 | true, 217 | AuditEvent{ 218 | Serial: "403", 219 | Timestamp: "1464505810.566", 220 | Type: "AVC", 221 | Data: map[string]string{ 222 | "auid": "4294967295", "exe": `"/opt/google/chrome/chrome"`, "sig": "0", "arch": "c000003e", "syscall": "273", "compat": "0", "code": "0x50000", "uid": "1000", "gid": "1000", "ses": "4294967295", "pid": "4078", "comm": `"chrome"`, "ip": "0x7fb359e4d694"}, 223 | }, 224 | }, 225 | { 226 | `audit(1464505927.046:474): pid=1 uid=0 auid=4294967295 ses=4294967295 unit=lm-sensors comm="systemd" exe="/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'`, 227 | AUDIT_AVC, 228 | nil, 229 | true, 230 | AuditEvent{ 231 | Serial: "474", 232 | Timestamp: "1464505927.046", 233 | Type: "AVC", 234 | Data: map[string]string{ 235 | "uid": "0", "exe": `"/lib/systemd/systemd"`, "hostname": "?", "addr": "?", "terminal": "?", "res": "success", "pid": "1", "auid": "4294967295", "ses": "4294967295", "unit": "lm-sensors", "comm": `"systemd"`}, 236 | }, 237 | }, 238 | { 239 | `audit(1464505927.314:508): pid=1 uid=0 auid=4294967295 ses=4294967295 unit=rc-local comm="systemd" exe="/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'`, 240 | AUDIT_AVC, 241 | nil, 242 | true, 243 | AuditEvent{ 244 | Serial: "508", 245 | Timestamp: "1464505927.314", 246 | Type: "AVC", 247 | Data: map[string]string{ 248 | "pid": "1", "hostname": "?", "addr": "?", "unit": "rc-local", "comm": `"systemd"`, "exe": `"/lib/systemd/systemd"`, "terminal": "?", "res": "success", "uid": "0", "auid": "4294967295", "ses": "4294967295"}, 249 | }, 250 | }, 251 | { 252 | `audit(1464550921.784:3509): auid=4294967295 uid=1000 gid=1000 ses=4294967295 pid=14869 comm="chrome" exe="/opt/google/chrome/chrome" sig=0 arch=c000003e syscall=273 compat=0 ip=0x7f26b8828694 code=0x50000`, 253 | AUDIT_AVC, 254 | nil, 255 | true, 256 | AuditEvent{ 257 | Serial: "3509", 258 | Timestamp: "1464550921.784", 259 | Type: "AVC", 260 | Data: map[string]string{ 261 | "syscall": "273", "compat": "0", "ip": "0x7f26b8828694", "code": "0x50000", "auid": "4294967295", "uid": "1000", "gid": "1000", "sig": "0", "arch": "c000003e", "ses": "4294967295", "pid": "14869", "comm": `"chrome"`, "exe": `"/opt/google/chrome/chrome"`}, 262 | }, 263 | }, 264 | { 265 | `audit(1170021493.977:293): avc: denied { read write } for pid=13010 comm="pickup" name="maildrop" dev=hda7 ino=14911367 scontext=system_u:system_r:postfix_pickup_t:s0 tcontext=system_u:object_r:postfix_spool_maildrop_t:s0 tclass=dir`, 266 | AUDIT_AVC, 267 | nil, 268 | true, 269 | AuditEvent{ 270 | Serial: "293", 271 | Timestamp: "1170021493.977", 272 | Type: "AVC", 273 | Data: map[string]string{ 274 | "scontext": "system_u:system_r:postfix_pickup_t:s0", "seresult": "denied", "comm": `"pickup"`, "name": `"maildrop"`, "dev": "hda7", "ino": "14911367", "tcontext": "system_u:object_r:postfix_spool_maildrop_t:s0", "tclass": "dir", "seperms": "read,write", "pid": "13010"}, 275 | }, 276 | }, 277 | } 278 | 279 | func TestMalformedPrefix(t *testing.T) { 280 | tmsg := []struct { 281 | msg string 282 | msgType auditConstant 283 | err string 284 | }{ 285 | {"xyzabc", AUDIT_AVC, "malformed, missing audit prefix"}, 286 | {`audit(1464163771`, AUDIT_AVC, "malformed, can't locate start of fields"}, 287 | {`audit(1464176620.068:1445`, AUDIT_AVC, "malformed, can't locate end of prefix"}, 288 | } 289 | for _, m := range tmsg { 290 | _, err := ParseAuditEvent(m.msg, m.msgType, false) 291 | if err == nil { 292 | t.Fatalf("ParseAuditEvent should have failed on %q", m.msg) 293 | } 294 | if err.Error() != m.err { 295 | t.Fatalf("ParseAuditEvent failed, but error %q was unexpected", err) 296 | } 297 | } 298 | } 299 | 300 | func TestNativeParser(t *testing.T) { 301 | for i, tt := range auditTests { 302 | x, err := ParseAuditEvent(tt.msg, tt.msgType, false) 303 | if err != tt.expected { 304 | t.Fatalf("ParseAuditEvent: event %v had unexpected error value", i) 305 | } 306 | if tt.match { 307 | checkEvent(i, &tt.event, x, t) 308 | } 309 | } 310 | } 311 | 312 | func BenchmarkNativeParser(b *testing.B) { 313 | for n := 0; n < b.N; n++ { 314 | ParseAuditEvent(`audit(1226874073.147:96): avc: denied { getattr } for pid=2465 comm="httpd" path="/var/www/html/file1 space" dev=dm-0 ino=284133 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:samba_share_t:s0 tclass=file`, AUDIT_AVC, true) 315 | } 316 | } 317 | 318 | func BenchmarkNativeParserTable(b *testing.B) { 319 | for n := 0; n < b.N; n++ { 320 | for _, x := range auditTests { 321 | ParseAuditEvent(x.msg, AUDIT_AVC, true) 322 | } 323 | } 324 | } 325 | 326 | // checkEvent compares auditEvent a to b, ensuring they are identical. 327 | func checkEvent(eventid int, a *AuditEvent, b *AuditEvent, t *testing.T) { 328 | if a.Serial != b.Serial { 329 | t.Fatalf("audit event %v serial did not match", eventid) 330 | } 331 | if a.Timestamp != b.Timestamp { 332 | t.Fatalf("audit event %v timestamp did not match", eventid) 333 | } 334 | if a.Type != b.Type { 335 | t.Fatalf("audit event %v type did not match", eventid) 336 | } 337 | if !reflect.DeepEqual(a.Data, b.Data) { 338 | t.Fatalf("audit event %v data was not equal", eventid) 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /rules_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package libaudit 6 | 7 | import ( 8 | "io/ioutil" 9 | "os" 10 | "testing" 11 | ) 12 | 13 | var expectedRules = []string{ 14 | "-w /etc/libaudit.conf -p wa -k audit", 15 | "-w /etc/rsyslog.conf -p wa -k syslog", 16 | "-a always,exit-F arch=b64 -S personality -F key=bypass", 17 | "-a never,exit -F path=/bin/ls -F perm=x", 18 | "-a always,exit-F arch=b64 -S execve -F key=exec", 19 | "-a always,exit -S clone,fork,vfork", 20 | "-a always,exit -S adjtimex,settimeofday -F key=time-change", 21 | "-a always,exit-F arch=b64 -S rename,renameat -F auid>=1000 -F key=rename", 22 | } 23 | 24 | func TestSetRules(t *testing.T) { 25 | if os.Getuid() != 0 { 26 | t.Skipf("skipping test, not root user") 27 | } 28 | 29 | jsonRules, err := ioutil.ReadFile("./testdata/rules.json") 30 | if err != nil { 31 | t.Fatalf("ioutil.ReadFile: %v", err) 32 | } 33 | 34 | s, err := NewNetlinkConnection() 35 | if err != nil { 36 | t.Fatalf("NewNetlinkConnection: %v", err) 37 | } 38 | err = DeleteAllRules(s) 39 | if err != nil { 40 | t.Fatalf("DeleteAllRules: %v", err) 41 | } 42 | 43 | _, err = SetRules(s, jsonRules) 44 | if err != nil { 45 | t.Fatalf("SetRules: %v", err) 46 | } 47 | s.Close() 48 | 49 | // Open up a new connection before we list the rules 50 | x, err := NewNetlinkConnection() 51 | if err != nil { 52 | t.Fatalf("NewNetlinkConnection: %v", err) 53 | } 54 | 55 | setRules, err := ListAllRules(x) 56 | if err != nil { 57 | t.Fatalf("ListAllRules: %v", err) 58 | } 59 | if len(setRules) != len(expectedRules) { 60 | t.Fatalf("number of set rules unexpected, wanted %v got %v", len(expectedRules), 61 | len(setRules)) 62 | } 63 | for i := range setRules { 64 | if setRules[i] != expectedRules[i] { 65 | t.Fatalf("expected rule %q, got rule %q", expectedRules[i], setRules[i]) 66 | } 67 | } 68 | x.Close() 69 | } 70 | 71 | // Try to load a rule set with strict path checking enabled, where the path in a watch rule is 72 | // nonexistent; should fail. 73 | func TestSetRulesStrictPathFail(t *testing.T) { 74 | if os.Getuid() != 0 { 75 | t.Skipf("skipping test, not root user") 76 | } 77 | 78 | jsonRules, err := ioutil.ReadFile("./testdata/strictpathfail.json") 79 | if err != nil { 80 | t.Fatalf("ioutil.ReadFile: %v", err) 81 | } 82 | 83 | s, err := NewNetlinkConnection() 84 | if err != nil { 85 | t.Fatalf("NewNetlinkConnection: %v", err) 86 | } 87 | err = DeleteAllRules(s) 88 | if err != nil { 89 | t.Fatalf("DeleteAllRules: %v", err) 90 | } 91 | 92 | _, err = SetRules(s, jsonRules) 93 | if err == nil { 94 | t.Fatalf("SetRules should have failed on nonexistent path") 95 | } 96 | s.Close() 97 | } 98 | 99 | // Try to load a rule set with strict path checking disabled, where the path in a watch rule is 100 | // nonexistent; should succeed but ignore the invalid rule. 101 | func TestSetRulesNoStrictPath(t *testing.T) { 102 | if os.Getuid() != 0 { 103 | t.Skipf("skipping test, not root user") 104 | } 105 | 106 | jsonRules, err := ioutil.ReadFile("./testdata/badpathnostrictpath.json") 107 | if err != nil { 108 | t.Fatalf("ioutil.ReadFile: %v", err) 109 | } 110 | 111 | s, err := NewNetlinkConnection() 112 | if err != nil { 113 | t.Fatalf("NewNetlinkConnection: %v", err) 114 | } 115 | err = DeleteAllRules(s) 116 | if err != nil { 117 | t.Fatalf("DeleteAllRules: %v", err) 118 | } 119 | 120 | warnings, err := SetRules(s, jsonRules) 121 | if err != nil { 122 | t.Fatalf("SetRules: %v", err) 123 | } 124 | 125 | // We should have gotten one warning back 126 | if len(warnings) != 1 { 127 | t.Fatalf("SetRules: should have returned 1 warning") 128 | } 129 | 130 | // Open up a new connection before we list the rules 131 | x, err := NewNetlinkConnection() 132 | if err != nil { 133 | t.Fatalf("NewNetlinkConnection: %v", err) 134 | } 135 | 136 | setRules, err := ListAllRules(x) 137 | if err != nil { 138 | t.Fatalf("ListAllRules: %v", err) 139 | } 140 | // We should have 1 rule here, since the test data set contains 2 rules, one of which 141 | // should have been ignored. 142 | expectedRules := 1 143 | if len(setRules) != expectedRules { 144 | t.Fatalf("number of set rules unexpected, wanted %v got %v", expectedRules, 145 | len(setRules)) 146 | } 147 | s.Close() 148 | } 149 | -------------------------------------------------------------------------------- /s2i_type_conversion.json: -------------------------------------------------------------------------------- 1 | { 2 | "machine" : [ 3 | { 4 | "string": "armeb", 5 | "s2iS" : 0, 6 | "s2iI" : 8 7 | }, 8 | { 9 | "name": "armv5tejl", 10 | "s2iS" : 6, 11 | "s2iI" : 8 12 | }, 13 | { 14 | "name": "armv7l", 15 | "s2iS" : 16, 16 | "s2iI" : 8 17 | }, 18 | { 19 | "name": "i386", 20 | "s2iS" : 23, 21 | "s2iI" : 0 22 | }, 23 | { 24 | "name": "i486", 25 | "s2iS" : 28, 26 | "s2iI" : 0 27 | }, 28 | { 29 | "name": "i586", 30 | "s2iS" : 33, 31 | "s2iI" : 0 32 | }, 33 | { 34 | "name": "i686", 35 | "s2iS" : 38, 36 | "s2iI" : 0 37 | }, 38 | { 39 | "name": "ia64", 40 | "s2iS" : 43, 41 | "s2iI" : 2 42 | }, 43 | { 44 | "name": "ppc", 45 | "s2iS" : 48, 46 | "s2iI" : 4 47 | }, 48 | { 49 | "name": "ppc64", 50 | "s2iS" : 52, 51 | "s2iI" : 3 52 | }, 53 | { 54 | "name": "s390", 55 | "s2iS" : 58, 56 | "s2iI" : 6 57 | }, 58 | { 59 | "name": "s390x", 60 | "s2iS" : 63, 61 | "s2iI" : 5 62 | }, 63 | { 64 | "name": "x86_64", 65 | "s2iS" : 69, 66 | "s2iI" : 1 67 | } 68 | ], 69 | 70 | "errStrings" : [ 71 | { 72 | "string": "E2BIG",, 73 | "s2iS" : 0, 74 | "s2iI" : 8 75 | }, 76 | { 77 | "name": "EACCES", 78 | "s2iS" : 6, 79 | "s2iI" : 8 80 | }, 81 | { 82 | "name": "EADDRINUSE", 83 | "s2iS" : 16, 84 | "s2iI" : 8 85 | }, 86 | { 87 | "name": ,"EADDRNOTAVAIL", 88 | "s2iS" : 23, 89 | "s2iI" : 0 90 | }, 91 | { 92 | "name": ,"EADV", 93 | "s2iS" : 28, 94 | "s2iI" : 0 95 | }, 96 | { 97 | "name": ,"EAFNOSUPPORT", 98 | "s2iS" : 33, 99 | "s2iI" : 0 100 | }, 101 | { 102 | "name": ,"EAGAIN", 103 | "s2iS" : 38, 104 | "s2iI" : 0 105 | }, 106 | { 107 | "name": ,"EALREADY", 108 | "s2iS" : 43, 109 | "s2iI" : 0 110 | }, 111 | { 112 | "name": ,"EBADE", 113 | "s2iS" : 48, 114 | "s2iI" : 0 115 | }, 116 | { 117 | "name": ,"EBADF", 118 | "s2iS" : 52, 119 | "s2iI" : 0 120 | }, 121 | { 122 | "name": "EBADFD", 123 | "s2iS" : 58, 124 | "s2iI" : 0 125 | }, 126 | { 127 | "name": "EBADMSG", 128 | "s2iS" : 63, 129 | "s2iI" : 0 130 | }, 131 | { 132 | "name": "EBADR", 133 | "s2iS" : 69, 134 | "s2iI" : 0 135 | }, 136 | { 137 | "name": "EBADRQC", 138 | "s2iS" : 69, 139 | "s2iI" : 0 140 | }, 141 | { 142 | "name": ,"EBADSLT", 143 | "s2iS" : 69, 144 | "s2iI" : 0 145 | }, 146 | { 147 | "name": ,"EBFONT", 148 | "s2iS" : 69, 149 | "s2iI" : 0 150 | }, 151 | { 152 | "name": "EBUSY", 153 | "s2iS" : 69, 154 | "s2iI" : 0 155 | }, 156 | { 157 | "name": "ECANCELED", 158 | "s2iS" : 69, 159 | "s2iI" : 0 160 | }, 161 | { 162 | "name": "ECHILD", 163 | "s2iS" : 69, 164 | "s2iI" : 0 165 | }, 166 | { 167 | "name": "ECHRNG", 168 | "s2iS" : 69, 169 | "s2iI" : 0 170 | }, 171 | { 172 | "name": "ECOMM", 173 | "s2iS" : 69, 174 | "s2iI" : 0 175 | }, 176 | { 177 | "name": "ECONNABORTED", 178 | "s2iS" : 69, 179 | "s2iI" : 0 180 | }, 181 | { 182 | "name": "ECONNREFUSED", 183 | "s2iS" : 69, 184 | "s2iI" : 0 185 | }, 186 | { 187 | "name": "ECONNRESET", 188 | "s2iS" : 69, 189 | "s2iI" : 0 190 | }, 191 | { 192 | "name": "EDEADLK", 193 | "s2iS" : 69, 194 | "s2iI" : 0 195 | }, 196 | { 197 | "name": "EDEADLOCK", 198 | "s2iS" : 69, 199 | "s2iI" : 0 200 | }, 201 | { 202 | "name": "EDESTADDRREQ", 203 | "s2iS" : 69, 204 | "s2iI" : 0 205 | }, 206 | { 207 | "name": "EDOM", 208 | "s2iS" : 69, 209 | "s2iI" : 0 210 | }, 211 | { 212 | "name": "EDOTDOT", 213 | "s2iS" : 69, 214 | "s2iI" : 0 215 | }, 216 | { 217 | "name": "EDQUOT", 218 | "s2iS" : 69, 219 | "s2iI" : 0 220 | }, 221 | { 222 | "name": "EEXIST", 223 | "s2iS" : 69, 224 | "s2iI" : 0 225 | }, 226 | { 227 | "name": "EFAULT", 228 | "s2iS" : 69, 229 | "s2iI" : 0 230 | }, 231 | { 232 | "name": "EFBIG", 233 | "s2iS" : 69, 234 | "s2iI" : 0 235 | }, 236 | { 237 | "name": "EHOSTDOWN", 238 | "s2iS" : 69, 239 | "s2iI" : 0 240 | } 241 | ] 242 | } 243 | 244 | ////////// Need to make message type follow http://www.filewatcher.com/p/audit-debuginfo-1.7.7-6.el5.ia64.rpm.955920/usr/src/debug/audit-1.7.7/lib/msg_typetabs.h.html to make it 245 | -------------------------------------------------------------------------------- /testdata/badpathnostrictpath.json: -------------------------------------------------------------------------------- 1 | { 2 | "audit_rules": [ 3 | { 4 | "key": "nonexist", 5 | "path": "/non/existent/path", 6 | "permission": "wa", 7 | "strict_path_check": false 8 | }, 9 | { 10 | "actions": [ 11 | "always", 12 | "exit" 13 | ], 14 | "fields": [ 15 | { 16 | "name": "arch", 17 | "op": "eq", 18 | "value": 64 19 | } 20 | ], 21 | "key": "bypass", 22 | "syscalls": [ 23 | "personality" 24 | ] 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /testdata/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "audit_rules": [ 3 | { 4 | "key": "audit", 5 | "path": "/etc/libaudit.conf", 6 | "permission": "wa" 7 | }, 8 | { 9 | "key": "syslog", 10 | "path": "/etc/rsyslog.conf", 11 | "permission": "wa" 12 | }, 13 | { 14 | "actions": [ 15 | "always", 16 | "exit" 17 | ], 18 | "fields": [ 19 | { 20 | "name": "arch", 21 | "op": "eq", 22 | "value": 64 23 | } 24 | ], 25 | "key": "bypass", 26 | "syscalls": [ 27 | "personality" 28 | ] 29 | }, 30 | { 31 | "actions": [ 32 | "exit", 33 | "never" 34 | ], 35 | "fields": [ 36 | { 37 | "name": "path", 38 | "op": "eq", 39 | "value": "/bin/ls" 40 | }, 41 | { 42 | "name": "perm", 43 | "op": "eq", 44 | "value": "x" 45 | } 46 | ] 47 | }, 48 | { 49 | "actions": [ 50 | "exit", 51 | "always" 52 | ], 53 | "fields": [ 54 | { 55 | "name": "arch", 56 | "op": "eq", 57 | "value": 64 58 | } 59 | ], 60 | "key": "exec", 61 | "syscalls": [ 62 | "execve" 63 | ] 64 | }, 65 | { 66 | "actions": [ 67 | "entry", 68 | "always" 69 | ], 70 | "syscalls": [ 71 | "clone", 72 | "fork", 73 | "vfork" 74 | ] 75 | }, 76 | { 77 | "actions": [ 78 | "always", 79 | "exit" 80 | ], 81 | "syscalls": [ 82 | "settimeofday", 83 | "adjtimex" 84 | ], 85 | "key": "time-change" 86 | }, 87 | { 88 | "actions": [ 89 | "always", 90 | "exit" 91 | ], 92 | "fields": [ 93 | { 94 | "name": "arch", 95 | "op": "eq", 96 | "value": 64 97 | }, 98 | { 99 | "name": "auid", 100 | "op": "gt_or_eq", 101 | "value": 1000 102 | } 103 | ], 104 | "key": "rename", 105 | "syscalls": [ 106 | "rename", 107 | "renameat" 108 | ] 109 | } 110 | ] 111 | } 112 | -------------------------------------------------------------------------------- /testdata/strictpathfail.json: -------------------------------------------------------------------------------- 1 | { 2 | "audit_rules": [ 3 | { 4 | "key": "nonexist", 5 | "path": "/non/existent/path", 6 | "permission": "wa", 7 | "strict_path_check": true 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | sudo: false 3 | 4 | script: go test -v 5 | 6 | go: 7 | - 1.2 8 | - 1.3 9 | - 1.4 10 | - tip 11 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Ryan Hileman 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/lunixbochs/struc.svg?branch=master)](https://travis-ci.org/lunixbochs/struc) 2 | 3 | struc 4 | ==== 5 | 6 | Struc exists to pack and unpack C-style structures from bytes, which is useful for binary files and network protocols. It could be considered an alternative to `encoding/binary`, which requires massive boilerplate for some similar operations. 7 | 8 | Take a look at an [example comparing `struc` and `encoding/binary`](https://bochs.info/p/cxvm9) 9 | 10 | Struc considers usability first. That said, it does cache reflection data and aims to be competitive with `encoding/binary` struct packing in every way, including performance. 11 | 12 | Example struct 13 | ---- 14 | 15 | ```Go 16 | type Example struct { 17 | Var int `struc:"int32,sizeof=Str"` 18 | Str string 19 | Weird []byte `struc:"[8]int64"` 20 | Var []int `struc:"[]int32,little"` 21 | } 22 | ``` 23 | 24 | Struct tag format 25 | ---- 26 | 27 | - ```Var []int `struc:"[]int32,little,sizeof=StringField"` ``` will pack Var as a slice of little-endian int32, and link it as the size of `StringField`. 28 | - `sizeof=`: Indicates this field is a number used to track the length of a another field. `sizeof` fields are automatically updated on `Pack()` based on the current length of the tracked field, and are used to size the target field during `Unpack()`. 29 | - Bare values will be parsed as type and endianness. 30 | 31 | Endian formats 32 | ---- 33 | 34 | - `big` (default) 35 | - `little` 36 | 37 | Recognized types 38 | ---- 39 | 40 | - `pad` - this type ignores field contents and is backed by a `[length]byte` containing nulls 41 | - `bool` 42 | - `byte` 43 | - `int8`, `uint8` 44 | - `int16`, `uint16` 45 | - `int32`, `uint32` 46 | - `int64`, `uint64` 47 | - `float32` 48 | - `float64` 49 | 50 | Types can be indicated as arrays/slices using `[]` syntax. Example: `[]int64`, `[8]int32`. 51 | 52 | Bare slice types (those with no `[size]`) must have a linked `Sizeof` field. 53 | 54 | Private fields are ignored when packing and unpacking. 55 | 56 | Example code 57 | ---- 58 | 59 | ```Go 60 | package main 61 | 62 | import ( 63 | "bytes" 64 | "github.com/lunixbochs/struc" 65 | ) 66 | 67 | type Example struct { 68 | A int `struc:"big"` 69 | 70 | // B will be encoded/decoded as a 16-bit int (a "short") 71 | // but is stored as a native int in the struct 72 | B int `struc:"int16"` 73 | 74 | // the sizeof key links a buffer's size to any int field 75 | Size int `struc:"int8,little,sizeof=Str"` 76 | Str string 77 | 78 | // you can get freaky if you want 79 | Str2 string `struc:"[5]int64"` 80 | } 81 | 82 | func main() { 83 | var buf bytes.Buffer 84 | t := &Example{1, 2, 0, "test", "test2"} 85 | err := struc.Pack(&buf, t) 86 | o := &Example{} 87 | err = struc.Unpack(&buf, o) 88 | } 89 | ``` 90 | 91 | Benchmark 92 | ---- 93 | 94 | `BenchmarkEncode` uses struc. `Stdlib` benchmarks use equivalent `encoding/binary` code. `Manual` encodes without any reflection, and should be considered an upper bound on performance (which generated code based on struc definitions should be able to achieve). 95 | 96 | ``` 97 | BenchmarkEncode 1000000 1265 ns/op 98 | BenchmarkStdlibEncode 1000000 1855 ns/op 99 | BenchmarkManualEncode 5000000 284 ns/op 100 | BenchmarkDecode 1000000 1259 ns/op 101 | BenchmarkStdlibDecode 1000000 1656 ns/op 102 | BenchmarkManualDecode 20000000 89.0 ns/op 103 | ``` 104 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/bench_test.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "testing" 7 | ) 8 | 9 | type BenchExample struct { 10 | Test [5]byte 11 | A int32 12 | B, C, D int16 13 | Test2 [4]byte 14 | Length int32 15 | } 16 | 17 | type BenchStrucExample struct { 18 | Test [5]byte `struc:"[5]byte"` 19 | A int `struc:"int32"` 20 | B, C, D int `struc:"int16"` 21 | Test2 [4]byte `struc:"[4]byte"` 22 | Length int `struc:"int32,sizeof=Data"` 23 | Data []byte 24 | } 25 | 26 | var benchRef = &BenchExample{ 27 | [5]byte{1, 2, 3, 4, 5}, 28 | 1, 2, 3, 4, 29 | [4]byte{1, 2, 3, 4}, 30 | 8, 31 | } 32 | 33 | var eightBytes = []byte("8bytestr") 34 | 35 | var benchStrucRef = &BenchStrucExample{ 36 | [5]byte{1, 2, 3, 4, 5}, 37 | 1, 2, 3, 4, 38 | [4]byte{1, 2, 3, 4}, 39 | 8, eightBytes, 40 | } 41 | 42 | func BenchmarkEncode(b *testing.B) { 43 | for i := 0; i < b.N; i++ { 44 | var buf bytes.Buffer 45 | err := Pack(&buf, benchStrucRef) 46 | if err != nil { 47 | b.Fatal(err) 48 | } 49 | } 50 | } 51 | 52 | func BenchmarkStdlibEncode(b *testing.B) { 53 | for i := 0; i < b.N; i++ { 54 | var buf bytes.Buffer 55 | err := binary.Write(&buf, binary.BigEndian, benchRef) 56 | if err != nil { 57 | b.Fatal(err) 58 | } 59 | _, err = buf.Write(eightBytes) 60 | if err != nil { 61 | b.Fatal(err) 62 | } 63 | } 64 | } 65 | 66 | func BenchmarkManualEncode(b *testing.B) { 67 | order := binary.BigEndian 68 | s := benchStrucRef 69 | for i := 0; i < b.N; i++ { 70 | var buf bytes.Buffer 71 | tmp := make([]byte, 29) 72 | copy(tmp[0:5], s.Test[:]) 73 | order.PutUint32(tmp[5:9], uint32(s.A)) 74 | order.PutUint16(tmp[9:11], uint16(s.B)) 75 | order.PutUint16(tmp[11:13], uint16(s.C)) 76 | order.PutUint16(tmp[13:15], uint16(s.D)) 77 | copy(tmp[15:19], s.Test2[:]) 78 | order.PutUint32(tmp[19:23], uint32(s.Length)) 79 | copy(tmp[23:], s.Data) 80 | _, err := buf.Write(tmp) 81 | if err != nil { 82 | b.Fatal(err) 83 | } 84 | } 85 | } 86 | 87 | func BenchmarkDecode(b *testing.B) { 88 | var out BenchStrucExample 89 | var buf bytes.Buffer 90 | if err := Pack(&buf, benchStrucRef); err != nil { 91 | b.Fatal(err) 92 | } 93 | bufBytes := buf.Bytes() 94 | for i := 0; i < b.N; i++ { 95 | buf := bytes.NewReader(bufBytes) 96 | err := Unpack(buf, &out) 97 | if err != nil { 98 | b.Fatal(err) 99 | } 100 | out.Data = nil 101 | } 102 | } 103 | 104 | func BenchmarkStdlibDecode(b *testing.B) { 105 | var out BenchExample 106 | var buf bytes.Buffer 107 | binary.Write(&buf, binary.BigEndian, *benchRef) 108 | _, err := buf.Write(eightBytes) 109 | if err != nil { 110 | b.Fatal(err) 111 | } 112 | bufBytes := buf.Bytes() 113 | for i := 0; i < b.N; i++ { 114 | buf := bytes.NewReader(bufBytes) 115 | err := binary.Read(buf, binary.BigEndian, &out) 116 | if err != nil { 117 | b.Fatal(err) 118 | } 119 | tmp := make([]byte, out.Length) 120 | _, err = buf.Read(tmp) 121 | if err != nil { 122 | b.Fatal(err) 123 | } 124 | } 125 | } 126 | 127 | func BenchmarkManualDecode(b *testing.B) { 128 | var o BenchStrucExample 129 | var buf bytes.Buffer 130 | if err := Pack(&buf, benchStrucRef); err != nil { 131 | b.Fatal(err) 132 | } 133 | tmp := buf.Bytes() 134 | order := binary.BigEndian 135 | for i := 0; i < b.N; i++ { 136 | copy(o.Test[:], tmp[0:5]) 137 | o.A = int(order.Uint32(tmp[5:9])) 138 | o.B = int(order.Uint16(tmp[9:11])) 139 | o.C = int(order.Uint16(tmp[11:13])) 140 | o.D = int(order.Uint16(tmp[13:15])) 141 | copy(o.Test2[:], tmp[15:19]) 142 | o.Length = int(order.Uint32(tmp[19:23])) 143 | o.Data = make([]byte, o.Length) 144 | copy(o.Data, tmp[23:]) 145 | } 146 | } 147 | 148 | func BenchmarkFullEncode(b *testing.B) { 149 | for i := 0; i < b.N; i++ { 150 | var buf bytes.Buffer 151 | if err := Pack(&buf, reference); err != nil { 152 | b.Fatal(err) 153 | } 154 | } 155 | } 156 | 157 | func BenchmarkFullDecode(b *testing.B) { 158 | var out Example 159 | for i := 0; i < b.N; i++ { 160 | buf := bytes.NewBuffer(referenceBytes) 161 | if err := Unpack(buf, &out); err != nil { 162 | b.Fatal(err) 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/binary.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | "reflect" 7 | ) 8 | 9 | type byteWriter struct { 10 | buf []byte 11 | pos int 12 | } 13 | 14 | func (b byteWriter) Write(p []byte) (int, error) { 15 | capacity := len(b.buf) - b.pos 16 | if capacity < len(p) { 17 | p = p[:capacity] 18 | } 19 | if len(p) > 0 { 20 | copy(b.buf[b.pos:], p) 21 | b.pos += len(p) 22 | } 23 | return len(p), nil 24 | } 25 | 26 | type binaryFallback reflect.Value 27 | 28 | func (b binaryFallback) String() string { 29 | return b.String() 30 | } 31 | 32 | func (b binaryFallback) Sizeof(val reflect.Value, options *Options) int { 33 | return binary.Size(val.Interface()) 34 | } 35 | 36 | func (b binaryFallback) Pack(buf []byte, val reflect.Value, options *Options) (int, error) { 37 | tmp := byteWriter{buf: buf} 38 | var order binary.ByteOrder = binary.BigEndian 39 | if options.Order != nil { 40 | order = options.Order 41 | } 42 | err := binary.Write(tmp, order, val.Interface()) 43 | return tmp.pos, err 44 | } 45 | 46 | func (b binaryFallback) Unpack(r io.Reader, val reflect.Value, options *Options) error { 47 | var order binary.ByteOrder = binary.BigEndian 48 | if options.Order != nil { 49 | order = options.Order 50 | } 51 | return binary.Read(r, order, val.Interface()) 52 | } 53 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/custom.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "io" 5 | "reflect" 6 | ) 7 | 8 | type Custom interface { 9 | Pack(p []byte, opt *Options) (int, error) 10 | Unpack(r io.Reader, length int, opt *Options) error 11 | Size(opt *Options) int 12 | String() string 13 | } 14 | 15 | type customFallback struct { 16 | custom Custom 17 | } 18 | 19 | func (c customFallback) Pack(p []byte, val reflect.Value, opt *Options) (int, error) { 20 | return c.custom.Pack(p, opt) 21 | } 22 | 23 | func (c customFallback) Unpack(r io.Reader, val reflect.Value, opt *Options) error { 24 | return c.custom.Unpack(r, 1, opt) 25 | } 26 | 27 | func (c customFallback) Sizeof(val reflect.Value, opt *Options) int { 28 | return c.custom.Size(opt) 29 | } 30 | 31 | func (c customFallback) String() string { 32 | return c.custom.String() 33 | } 34 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/custom_float16.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | "math" 7 | "strconv" 8 | ) 9 | 10 | type Float16 float64 11 | 12 | func (f *Float16) Pack(p []byte, opt *Options) (int, error) { 13 | order := opt.Order 14 | if order == nil { 15 | order = binary.BigEndian 16 | } 17 | sign := uint16(0) 18 | if *f < 0 { 19 | sign = 1 20 | } 21 | var frac, exp uint16 22 | if math.IsInf(float64(*f), 0) { 23 | exp = 0x1f 24 | frac = 0 25 | } else if math.IsNaN(float64(*f)) { 26 | exp = 0x1f 27 | frac = 1 28 | } else { 29 | bits := math.Float64bits(float64(*f)) 30 | exp64 := (bits >> 52) & 0x7ff 31 | if exp64 != 0 { 32 | exp = uint16((exp64 - 1023 + 15) & 0x1f) 33 | } 34 | frac = uint16((bits >> 42) & 0x3ff) 35 | } 36 | var out uint16 37 | out |= sign << 15 38 | out |= exp << 10 39 | out |= frac & 0x3ff 40 | order.PutUint16(p, out) 41 | return 2, nil 42 | } 43 | func (f *Float16) Unpack(r io.Reader, length int, opt *Options) error { 44 | order := opt.Order 45 | if order == nil { 46 | order = binary.BigEndian 47 | } 48 | var tmp [2]byte 49 | if _, err := r.Read(tmp[:]); err != nil { 50 | return err 51 | } 52 | val := order.Uint16(tmp[:2]) 53 | sign := (val >> 15) & 1 54 | exp := int16((val >> 10) & 0x1f) 55 | frac := val & 0x3ff 56 | if exp == 0x1f { 57 | if frac != 0 { 58 | *f = Float16(math.NaN()) 59 | } else { 60 | *f = Float16(math.Inf(int(sign)*-2 + 1)) 61 | } 62 | } else { 63 | var bits uint64 64 | bits |= uint64(sign) << 63 65 | bits |= uint64(frac) << 42 66 | if exp > 0 { 67 | bits |= uint64(exp-15+1023) << 52 68 | } 69 | *f = Float16(math.Float64frombits(bits)) 70 | } 71 | return nil 72 | } 73 | func (f *Float16) Size(opt *Options) int { 74 | return 2 75 | } 76 | func (f *Float16) String() string { 77 | return strconv.FormatFloat(float64(*f), 'g', -1, 32) 78 | } 79 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/custom_float16_test.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "math" 8 | "strconv" 9 | "strings" 10 | "testing" 11 | ) 12 | 13 | func TestFloat16(t *testing.T) { 14 | // test cases from https://en.wikipedia.org/wiki/Half-precision_floating-point_format#Half_precision_examples 15 | tests := []struct { 16 | B string 17 | F float64 18 | }{ 19 | //s expnt significand 20 | {"0 01111 0000000000", 1}, 21 | {"0 01111 0000000001", 1.0009765625}, 22 | {"1 10000 0000000000", -2}, 23 | {"0 11110 1111111111", 65504}, 24 | // {"0 00001 0000000000", 0.0000610352}, 25 | // {"0 00000 1111111111", 0.0000609756}, 26 | // {"0 00000 0000000001", 0.0000000596046}, 27 | {"0 00000 0000000000", 0}, 28 | // {"1 00000 0000000000", -0}, 29 | {"0 11111 0000000000", math.Inf(1)}, 30 | {"1 11111 0000000000", math.Inf(-1)}, 31 | {"0 01101 0101010101", 0.333251953125}, 32 | } 33 | for _, test := range tests { 34 | var buf bytes.Buffer 35 | f := Float16(test.F) 36 | if err := Pack(&buf, &f); err != nil { 37 | t.Error("pack failed:", err) 38 | continue 39 | } 40 | bitval, _ := strconv.ParseUint(strings.Replace(test.B, " ", "", -1), 2, 16) 41 | tmp := binary.BigEndian.Uint16(buf.Bytes()) 42 | if tmp != uint16(bitval) { 43 | t.Errorf("incorrect pack: %s != %016b (%f)", test.B, tmp, test.F) 44 | continue 45 | } 46 | var f2 Float16 47 | if err := Unpack(&buf, &f2); err != nil { 48 | t.Error("unpack failed:", err) 49 | continue 50 | } 51 | // let sprintf deal with (im)precision for me here 52 | if fmt.Sprintf("%f", f) != fmt.Sprintf("%f", f2) { 53 | t.Errorf("incorrect unpack: %016b %f != %f", bitval, f, f2) 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/custom_test.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "io" 7 | "strconv" 8 | "testing" 9 | ) 10 | 11 | type Int3 uint32 12 | 13 | func (i *Int3) Pack(p []byte, opt *Options) (int, error) { 14 | var tmp [4]byte 15 | binary.BigEndian.PutUint32(tmp[:], uint32(*i)) 16 | copy(p, tmp[1:]) 17 | return 3, nil 18 | } 19 | func (i *Int3) Unpack(r io.Reader, length int, opt *Options) error { 20 | var tmp [4]byte 21 | if _, err := r.Read(tmp[1:]); err != nil { 22 | return err 23 | } 24 | *i = Int3(binary.BigEndian.Uint32(tmp[:])) 25 | return nil 26 | } 27 | func (i *Int3) Size(opt *Options) int { 28 | return 3 29 | } 30 | func (i *Int3) String() string { 31 | return strconv.FormatUint(uint64(*i), 10) 32 | } 33 | 34 | func TestCustom(t *testing.T) { 35 | var buf bytes.Buffer 36 | var i Int3 = 3 37 | if err := Pack(&buf, &i); err != nil { 38 | t.Fatal(err) 39 | } 40 | if !bytes.Equal(buf.Bytes(), []byte{0, 0, 3}) { 41 | t.Fatal("error packing custom int") 42 | } 43 | var i2 Int3 44 | if err := Unpack(&buf, &i2); err != nil { 45 | t.Fatal(err) 46 | } 47 | if i2 != 3 { 48 | t.Fatal("error unpacking custom int") 49 | } 50 | } 51 | 52 | type Int3Struct struct { 53 | I Int3 54 | } 55 | 56 | func TestCustomStruct(t *testing.T) { 57 | var buf bytes.Buffer 58 | i := Int3Struct{3} 59 | if err := Pack(&buf, &i); err != nil { 60 | t.Fatal(err) 61 | } 62 | if !bytes.Equal(buf.Bytes(), []byte{0, 0, 3}) { 63 | t.Fatal("error packing custom int struct") 64 | } 65 | var i2 Int3Struct 66 | if err := Unpack(&buf, &i2); err != nil { 67 | t.Fatal(err) 68 | } 69 | if i2.I != 3 { 70 | t.Fatal("error unpacking custom int struct") 71 | } 72 | } 73 | 74 | // TODO: slices of custom types don't work yet 75 | /* 76 | type Int3SliceStruct struct { 77 | I [2]Int3 78 | } 79 | 80 | func TestCustomSliceStruct(t *testing.T) { 81 | var buf bytes.Buffer 82 | i := Int3SliceStruct{[2]Int3{3, 4}} 83 | if err := Pack(&buf, &i); err != nil { 84 | t.Fatal(err) 85 | } 86 | if !bytes.Equal(buf.Bytes(), []byte{0, 0, 3}) { 87 | t.Fatal("error packing custom int struct") 88 | } 89 | var i2 Int3SliceStruct 90 | if err := Unpack(&buf, &i2); err != nil { 91 | t.Fatal(err) 92 | } 93 | if i2.I[0] != 3 && i2.I[1] != 4 { 94 | t.Fatal("error unpacking custom int struct") 95 | } 96 | } 97 | */ 98 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/field.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "math" 8 | "reflect" 9 | ) 10 | 11 | type Field struct { 12 | Name string 13 | CanSet bool 14 | Ptr bool 15 | Index int 16 | Type Type 17 | defType Type 18 | Array bool 19 | Slice bool 20 | Len int 21 | Order binary.ByteOrder 22 | Sizeof []int 23 | Sizefrom []int 24 | Fields Fields 25 | kind reflect.Kind 26 | } 27 | 28 | func (f *Field) String() string { 29 | var out string 30 | if f.Type == Pad { 31 | return fmt.Sprintf("{type: Pad, len: %d}", f.Len) 32 | } else { 33 | out = fmt.Sprintf("type: %s, order: %v", f.Type.String(), f.Order) 34 | } 35 | if f.Sizefrom != nil { 36 | out += fmt.Sprintf(", sizefrom: %v", f.Sizefrom) 37 | } else if f.Len > 0 { 38 | out += fmt.Sprintf(", len: %d", f.Len) 39 | } 40 | if f.Sizeof != nil { 41 | out += fmt.Sprintf(", sizeof: %v", f.Sizeof) 42 | } 43 | return "{" + out + "}" 44 | } 45 | 46 | func (f *Field) Size(val reflect.Value, options *Options) int { 47 | typ := f.Type.Resolve(options) 48 | size := 0 49 | if typ == Struct { 50 | vals := []reflect.Value{val} 51 | if f.Slice { 52 | vals = make([]reflect.Value, val.Len()) 53 | for i := 0; i < val.Len(); i++ { 54 | vals[i] = val.Index(i) 55 | } 56 | } 57 | for _, val := range vals { 58 | size += f.Fields.Sizeof(val, options) 59 | } 60 | } else if typ == Pad { 61 | size = f.Len 62 | } else if f.Slice || f.kind == reflect.String { 63 | length := val.Len() 64 | if f.Len > 1 { 65 | length = f.Len 66 | } 67 | size = length * typ.Size() 68 | } else if typ == CustomType { 69 | return val.Addr().Interface().(Custom).Size(options) 70 | } else { 71 | size = typ.Size() 72 | } 73 | align := options.ByteAlign 74 | if align > 0 && size < align { 75 | size = align 76 | } 77 | return size 78 | } 79 | 80 | func (f *Field) packVal(buf []byte, val reflect.Value, length int, options *Options) (size int, err error) { 81 | order := f.Order 82 | if options.Order != nil { 83 | order = options.Order 84 | } 85 | if f.Ptr { 86 | val = val.Elem() 87 | } 88 | typ := f.Type.Resolve(options) 89 | switch typ { 90 | case Struct: 91 | return f.Fields.Pack(buf, val, options) 92 | case Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64: 93 | size = typ.Size() 94 | var n uint64 95 | switch f.kind { 96 | case reflect.Bool: 97 | if val.Bool() { 98 | n = 1 99 | } else { 100 | n = 0 101 | } 102 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 103 | n = uint64(val.Int()) 104 | default: 105 | n = val.Uint() 106 | } 107 | switch typ { 108 | case Bool: 109 | if n != 0 { 110 | buf[0] = 1 111 | } else { 112 | buf[0] = 0 113 | } 114 | case Int8, Uint8: 115 | buf[0] = byte(n) 116 | case Int16, Uint16: 117 | order.PutUint16(buf, uint16(n)) 118 | case Int32, Uint32: 119 | order.PutUint32(buf, uint32(n)) 120 | case Int64, Uint64: 121 | order.PutUint64(buf, uint64(n)) 122 | } 123 | case Float32, Float64: 124 | size = typ.Size() 125 | n := val.Float() 126 | switch typ { 127 | case Float32: 128 | order.PutUint32(buf, math.Float32bits(float32(n))) 129 | case Float64: 130 | order.PutUint64(buf, math.Float64bits(n)) 131 | } 132 | case String: 133 | switch f.kind { 134 | case reflect.String: 135 | size = val.Len() 136 | copy(buf, []byte(val.String())) 137 | default: 138 | // TODO: handle kind != bytes here 139 | size = val.Len() 140 | copy(buf, val.Bytes()) 141 | } 142 | case CustomType: 143 | return val.Addr().Interface().(Custom).Pack(buf, options) 144 | default: 145 | panic(fmt.Sprintf("no pack handler for type: %s", typ)) 146 | } 147 | return 148 | } 149 | 150 | func (f *Field) Pack(buf []byte, val reflect.Value, length int, options *Options) (int, error) { 151 | typ := f.Type.Resolve(options) 152 | if typ == Pad { 153 | for i := 0; i < length; i++ { 154 | buf[i] = 0 155 | } 156 | return length, nil 157 | } 158 | if f.Slice { 159 | // special case strings and byte slices for performance 160 | end := val.Len() 161 | if !f.Array && typ == Uint8 && (f.defType == Uint8 || f.kind == reflect.String) { 162 | var tmp []byte 163 | if f.kind == reflect.String { 164 | tmp = []byte(val.String()) 165 | } else { 166 | tmp = val.Bytes() 167 | } 168 | copy(buf, tmp) 169 | if end < length { 170 | // TODO: allow configuring pad byte? 171 | rep := bytes.Repeat([]byte{0}, length-end) 172 | copy(buf[end:], rep) 173 | return length, nil 174 | } 175 | return val.Len(), nil 176 | } 177 | pos := 0 178 | var zero reflect.Value 179 | if end < length { 180 | zero = reflect.Zero(val.Type().Elem()) 181 | } 182 | for i := 0; i < length; i++ { 183 | cur := zero 184 | if i < end { 185 | cur = val.Index(i) 186 | } 187 | if n, err := f.packVal(buf[pos:], cur, 1, options); err != nil { 188 | return pos, err 189 | } else { 190 | pos += n 191 | } 192 | } 193 | return pos, nil 194 | } else { 195 | return f.packVal(buf, val, length, options) 196 | } 197 | } 198 | 199 | func (f *Field) unpackVal(buf []byte, val reflect.Value, length int, options *Options) error { 200 | order := f.Order 201 | if options.Order != nil { 202 | order = options.Order 203 | } 204 | if f.Ptr { 205 | val = val.Elem() 206 | } 207 | typ := f.Type.Resolve(options) 208 | switch typ { 209 | case Float32, Float64: 210 | var n float64 211 | switch typ { 212 | case Float32: 213 | n = float64(math.Float32frombits(order.Uint32(buf))) 214 | case Float64: 215 | n = math.Float64frombits(order.Uint64(buf)) 216 | } 217 | switch f.kind { 218 | case reflect.Float32, reflect.Float64: 219 | val.SetFloat(n) 220 | default: 221 | return fmt.Errorf("struc: refusing to unpack float into field %s of type %s", f.Name, f.kind.String()) 222 | } 223 | case Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64: 224 | var n uint64 225 | switch typ { 226 | case Bool, Int8, Uint8: 227 | n = uint64(buf[0]) 228 | case Int16, Uint16: 229 | n = uint64(order.Uint16(buf)) 230 | case Int32, Uint32: 231 | n = uint64(order.Uint32(buf)) 232 | case Int64, Uint64: 233 | n = uint64(order.Uint64(buf)) 234 | } 235 | switch f.kind { 236 | case reflect.Bool: 237 | val.SetBool(n != 0) 238 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 239 | val.SetInt(int64(n)) 240 | default: 241 | val.SetUint(n) 242 | } 243 | default: 244 | panic(fmt.Sprintf("no unpack handler for type: %s", typ)) 245 | } 246 | return nil 247 | } 248 | 249 | func (f *Field) Unpack(buf []byte, val reflect.Value, length int, options *Options) error { 250 | typ := f.Type.Resolve(options) 251 | if typ == Pad || f.kind == reflect.String { 252 | if typ == Pad { 253 | return nil 254 | } else { 255 | val.SetString(string(buf)) 256 | return nil 257 | } 258 | } else if f.Slice { 259 | if val.Cap() < length { 260 | val.Set(reflect.MakeSlice(val.Type(), length, length)) 261 | } else if val.Len() < length { 262 | val.Set(val.Slice(0, length)) 263 | } 264 | // special case byte slices for performance 265 | if !f.Array && typ == Uint8 && f.defType == Uint8 { 266 | copy(val.Bytes(), buf[:length]) 267 | return nil 268 | } 269 | pos := 0 270 | size := typ.Size() 271 | for i := 0; i < length; i++ { 272 | if err := f.unpackVal(buf[pos:pos+size], val.Index(i), 1, options); err != nil { 273 | return err 274 | } 275 | pos += size 276 | } 277 | return nil 278 | } else { 279 | return f.unpackVal(buf, val, length, options) 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/field_test.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | type badFloat struct { 9 | BadFloat int `struc:"float64"` 10 | } 11 | 12 | func TestBadFloatField(t *testing.T) { 13 | buf := bytes.NewReader([]byte("00000000")) 14 | err := Unpack(buf, &badFloat{}) 15 | if err == nil { 16 | t.Fatal("failed to error on bad float unpack") 17 | } 18 | } 19 | 20 | type emptyLengthField struct { 21 | Strlen int `struc:"sizeof=Str"` 22 | Str []byte 23 | } 24 | 25 | func TestEmptyLengthField(t *testing.T) { 26 | var buf bytes.Buffer 27 | s := &emptyLengthField{0, []byte("test")} 28 | o := &emptyLengthField{} 29 | if err := Pack(&buf, s); err != nil { 30 | t.Fatal(err) 31 | } 32 | if err := Unpack(&buf, o); err != nil { 33 | t.Fatal(err) 34 | } 35 | if !bytes.Equal(s.Str, o.Str) { 36 | t.Fatal("empty length field encode failed") 37 | } 38 | } 39 | 40 | type fixedSlicePad struct { 41 | Field []byte `struc:"[4]byte"` 42 | } 43 | 44 | func TestFixedSlicePad(t *testing.T) { 45 | var buf bytes.Buffer 46 | ref := []byte{0, 0, 0, 0} 47 | s := &fixedSlicePad{} 48 | if err := Pack(&buf, s); err != nil { 49 | t.Fatal(err) 50 | } 51 | if !bytes.Equal(buf.Bytes(), ref) { 52 | t.Fatal("implicit fixed slice pack failed") 53 | } 54 | if err := Unpack(&buf, s); err != nil { 55 | t.Fatal(err) 56 | } 57 | if !bytes.Equal(s.Field, ref) { 58 | t.Fatal("implicit fixed slice unpack failed") 59 | } 60 | } 61 | 62 | type sliceCap struct { 63 | Len int `struc:"sizeof=Field"` 64 | Field []byte 65 | } 66 | 67 | func TestSliceCap(t *testing.T) { 68 | var buf bytes.Buffer 69 | tmp := &sliceCap{0, []byte("1234")} 70 | if err := Pack(&buf, tmp); err != nil { 71 | t.Fatal(err) 72 | } 73 | tmp.Field = make([]byte, 0, 4) 74 | if err := Unpack(&buf, tmp); err != nil { 75 | t.Fatal(err) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/fields.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "io" 7 | "reflect" 8 | "strings" 9 | ) 10 | 11 | type Fields []*Field 12 | 13 | func (f Fields) SetByteOrder(order binary.ByteOrder) { 14 | for _, field := range f { 15 | field.Order = order 16 | } 17 | } 18 | 19 | func (f Fields) String() string { 20 | fields := make([]string, len(f)) 21 | for i, field := range f { 22 | fields[i] = field.String() 23 | } 24 | return "{" + strings.Join(fields, ", ") + "}" 25 | } 26 | 27 | func (f Fields) Sizeof(val reflect.Value, options *Options) int { 28 | for val.Kind() == reflect.Ptr { 29 | val = val.Elem() 30 | } 31 | size := 0 32 | for i, field := range f { 33 | v := val.Field(i) 34 | if v.CanSet() { 35 | size += field.Size(v, options) 36 | } 37 | } 38 | return size 39 | } 40 | 41 | func (f Fields) sizefrom(val reflect.Value, index []int) int { 42 | field := val.FieldByIndex(index) 43 | switch field.Kind() { 44 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 45 | return int(field.Int()) 46 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 47 | n := int(field.Uint()) 48 | // all the builtin array length types are native int 49 | // so this guards against weird truncation 50 | if n < 0 { 51 | return 0 52 | } 53 | return n 54 | default: 55 | name := val.Type().FieldByIndex(index).Name 56 | panic(fmt.Sprintf("sizeof field %T.%s not an integer type", val.Interface(), name)) 57 | } 58 | } 59 | 60 | func (f Fields) Pack(buf []byte, val reflect.Value, options *Options) (int, error) { 61 | for val.Kind() == reflect.Ptr { 62 | val = val.Elem() 63 | } 64 | pos := 0 65 | for i, field := range f { 66 | if !field.CanSet { 67 | continue 68 | } 69 | v := val.Field(i) 70 | length := field.Len 71 | if field.Sizefrom != nil { 72 | length = f.sizefrom(val, field.Sizefrom) 73 | } 74 | if length <= 0 && field.Slice { 75 | length = v.Len() 76 | } 77 | if field.Sizeof != nil { 78 | length := val.FieldByIndex(field.Sizeof).Len() 79 | switch field.kind { 80 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 81 | // allocating a new int here has fewer side effects (doesn't update the original struct) 82 | // but it's a wasteful allocation 83 | // the old method might work if we just cast the temporary int/uint to the target type 84 | v = reflect.New(v.Type()).Elem() 85 | v.SetInt(int64(length)) 86 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 87 | v = reflect.New(v.Type()).Elem() 88 | v.SetUint(uint64(length)) 89 | default: 90 | panic(fmt.Sprintf("sizeof field is not int or uint type: %s, %s", field.Name, v.Type())) 91 | } 92 | } 93 | if n, err := field.Pack(buf[pos:], v, length, options); err != nil { 94 | return n, err 95 | } else { 96 | pos += n 97 | } 98 | } 99 | return pos, nil 100 | } 101 | 102 | func (f Fields) Unpack(r io.Reader, val reflect.Value, options *Options) error { 103 | for val.Kind() == reflect.Ptr { 104 | val = val.Elem() 105 | } 106 | var tmp [8]byte 107 | var buf []byte 108 | for i, field := range f { 109 | if !field.CanSet { 110 | continue 111 | } 112 | v := val.Field(i) 113 | length := field.Len 114 | if field.Sizefrom != nil { 115 | length = f.sizefrom(val, field.Sizefrom) 116 | } 117 | if v.Kind() == reflect.Ptr && !v.Elem().IsValid() { 118 | v.Set(reflect.New(v.Type().Elem())) 119 | } 120 | if field.Type == Struct { 121 | if field.Slice { 122 | vals := reflect.MakeSlice(v.Type(), length, length) 123 | for i := 0; i < length; i++ { 124 | v := vals.Index(i) 125 | fields, err := parseFields(v) 126 | if err != nil { 127 | return err 128 | } 129 | if err := fields.Unpack(r, v, options); err != nil { 130 | return err 131 | } 132 | } 133 | v.Set(vals) 134 | } else { 135 | // TODO: DRY (we repeat the inner loop above) 136 | fields, err := parseFields(v) 137 | if err != nil { 138 | return err 139 | } 140 | if err := fields.Unpack(r, v, options); err != nil { 141 | return err 142 | } 143 | } 144 | continue 145 | } else { 146 | typ := field.Type.Resolve(options) 147 | if typ == CustomType { 148 | if err := v.Addr().Interface().(Custom).Unpack(r, length, options); err != nil { 149 | return err 150 | } 151 | } else { 152 | size := length * field.Type.Resolve(options).Size() 153 | if size < 8 { 154 | buf = tmp[:size] 155 | } else { 156 | buf = make([]byte, size) 157 | } 158 | if _, err := io.ReadFull(r, buf); err != nil { 159 | return err 160 | } 161 | err := field.Unpack(buf[:size], v, length, options) 162 | if err != nil { 163 | return err 164 | } 165 | } 166 | } 167 | } 168 | return nil 169 | } 170 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/fields_test.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "bytes" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | var refVal = reflect.ValueOf(reference) 10 | 11 | func TestFieldsParse(t *testing.T) { 12 | if _, err := parseFields(refVal); err != nil { 13 | t.Fatal(err) 14 | } 15 | } 16 | 17 | func TestFieldsString(t *testing.T) { 18 | fields, _ := parseFields(refVal) 19 | fields.String() 20 | } 21 | 22 | type sizefromStruct struct { 23 | Size1 uint `struc:"sizeof=Var1"` 24 | Var1 []byte 25 | Size2 int `struc:"sizeof=Var2"` 26 | Var2 []byte 27 | } 28 | 29 | func TestFieldsSizefrom(t *testing.T) { 30 | var test = sizefromStruct{ 31 | Var1: []byte{1, 2, 3}, 32 | Var2: []byte{4, 5, 6}, 33 | } 34 | var buf bytes.Buffer 35 | err := Pack(&buf, &test) 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | err = Unpack(&buf, &test) 40 | if err != nil { 41 | t.Fatal(err) 42 | } 43 | } 44 | 45 | type sizefromStructBad struct { 46 | Size1 string `struc:"sizeof=Var1"` 47 | Var1 []byte 48 | } 49 | 50 | func TestFieldsSizefromBad(t *testing.T) { 51 | var test = &sizefromStructBad{Var1: []byte{1, 2, 3}} 52 | var buf bytes.Buffer 53 | defer func() { 54 | if err := recover(); err == nil { 55 | t.Fatal("failed to panic on bad sizeof type") 56 | } 57 | }() 58 | Pack(&buf, &test) 59 | } 60 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/legacy.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | ) 7 | 8 | // Deprecated. Use PackWithOptions. 9 | func PackWithOrder(w io.Writer, data interface{}, order binary.ByteOrder) error { 10 | return PackWithOptions(w, data, &Options{Order: order}) 11 | } 12 | 13 | // Deprecated. Use UnpackWithOptions. 14 | func UnpackWithOrder(r io.Reader, data interface{}, order binary.ByteOrder) error { 15 | return UnpackWithOptions(r, data, &Options{Order: order}) 16 | } 17 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/packable_test.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | var packableReference = []byte{ 10 | 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 5, 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 11 | 9, 10, 11, 12, 13, 14, 15, 16, 12 | 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 13 | } 14 | 15 | func TestPackable(t *testing.T) { 16 | var ( 17 | buf bytes.Buffer 18 | 19 | i8 int8 = 1 20 | i16 int16 = 2 21 | i32 int32 = 3 22 | i64 int64 = 4 23 | u8 uint8 = 5 24 | u16 uint16 = 6 25 | u32 uint32 = 7 26 | u64 uint64 = 8 27 | 28 | u8a = [8]uint8{9, 10, 11, 12, 13, 14, 15, 16} 29 | u16a = [8]uint16{17, 18, 19, 20, 21, 22, 23, 24} 30 | ) 31 | // pack tests 32 | if err := Pack(&buf, i8); err != nil { 33 | t.Fatal(err) 34 | } 35 | if err := Pack(&buf, i16); err != nil { 36 | t.Fatal(err) 37 | } 38 | if err := Pack(&buf, i32); err != nil { 39 | t.Fatal(err) 40 | } 41 | if err := Pack(&buf, i64); err != nil { 42 | t.Fatal(err) 43 | } 44 | if err := Pack(&buf, u8); err != nil { 45 | t.Fatal(err) 46 | } 47 | if err := Pack(&buf, u16); err != nil { 48 | t.Fatal(err) 49 | } 50 | if err := Pack(&buf, u32); err != nil { 51 | t.Fatal(err) 52 | } 53 | if err := Pack(&buf, u64); err != nil { 54 | t.Fatal(err) 55 | } 56 | if err := Pack(&buf, u8a[:]); err != nil { 57 | t.Fatal(err) 58 | } 59 | if err := Pack(&buf, u16a[:]); err != nil { 60 | t.Fatal(err) 61 | } 62 | if !bytes.Equal(buf.Bytes(), packableReference) { 63 | fmt.Println(buf.Bytes()) 64 | fmt.Println(packableReference) 65 | t.Fatal("Packable Pack() did not match reference.") 66 | } 67 | // unpack tests 68 | i8 = 0 69 | i16 = 0 70 | i32 = 0 71 | i64 = 0 72 | u8 = 0 73 | u16 = 0 74 | u32 = 0 75 | u64 = 0 76 | if err := Unpack(&buf, &i8); err != nil { 77 | t.Fatal(err) 78 | } 79 | if err := Unpack(&buf, &i16); err != nil { 80 | t.Fatal(err) 81 | } 82 | if err := Unpack(&buf, &i32); err != nil { 83 | t.Fatal(err) 84 | } 85 | if err := Unpack(&buf, &i64); err != nil { 86 | t.Fatal(err) 87 | } 88 | if err := Unpack(&buf, &u8); err != nil { 89 | t.Fatal(err) 90 | } 91 | if err := Unpack(&buf, &u16); err != nil { 92 | t.Fatal(err) 93 | } 94 | if err := Unpack(&buf, &u32); err != nil { 95 | t.Fatal(err) 96 | } 97 | if err := Unpack(&buf, &u64); err != nil { 98 | t.Fatal(err) 99 | } 100 | if err := Unpack(&buf, u8a[:]); err != nil { 101 | t.Fatal(err) 102 | } 103 | if err := Unpack(&buf, u16a[:]); err != nil { 104 | t.Fatal(err) 105 | } 106 | // unpack checks 107 | if i8 != 1 || i16 != 2 || i32 != 3 || i64 != 4 { 108 | t.Fatal("Signed integer unpack failed.") 109 | } 110 | if u8 != 5 || u16 != 6 || u32 != 7 || u64 != 8 { 111 | t.Fatal("Unsigned integer unpack failed.") 112 | } 113 | for i := 0; i < 8; i++ { 114 | if u8a[i] != uint8(i+9) { 115 | t.Fatal("uint8 array unpack failed.") 116 | } 117 | } 118 | for i := 0; i < 8; i++ { 119 | if u16a[i] != uint16(i+17) { 120 | t.Fatal("uint16 array unpack failed.") 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/packer.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "io" 5 | "reflect" 6 | ) 7 | 8 | type Packer interface { 9 | Pack(buf []byte, val reflect.Value, options *Options) (int, error) 10 | Unpack(r io.Reader, val reflect.Value, options *Options) error 11 | Sizeof(val reflect.Value, options *Options) int 12 | String() string 13 | } 14 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/parse.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "fmt" 7 | "reflect" 8 | "regexp" 9 | "strconv" 10 | "strings" 11 | "sync" 12 | ) 13 | 14 | // struc:"int32,big,sizeof=Data" 15 | 16 | var tagWordsRe = regexp.MustCompile(`(\[|\b)[^"]+\b+$`) 17 | 18 | type strucTag struct { 19 | Type string 20 | Order binary.ByteOrder 21 | Sizeof string 22 | } 23 | 24 | func parseStrucTag(tag reflect.StructTag) *strucTag { 25 | t := &strucTag{ 26 | Order: binary.BigEndian, 27 | } 28 | tagStr := tag.Get("struc") 29 | if tagStr == "" { 30 | // someone's going to typo this (I already did once) 31 | // sorry if you made a module actually using this tag 32 | // and you're mad at me now 33 | tagStr = tag.Get("struct") 34 | } 35 | for _, s := range strings.Split(tagStr, ",") { 36 | if strings.HasPrefix(s, "sizeof=") { 37 | tmp := strings.SplitN(s, "=", 2) 38 | t.Sizeof = tmp[1] 39 | } else if s == "big" { 40 | t.Order = binary.BigEndian 41 | } else if s == "little" { 42 | t.Order = binary.LittleEndian 43 | } else { 44 | t.Type = s 45 | } 46 | } 47 | return t 48 | } 49 | 50 | var typeLenRe = regexp.MustCompile(`^\[(\d*)\]`) 51 | 52 | func parseField(f reflect.StructField) (fd *Field, err error) { 53 | tag := parseStrucTag(f.Tag) 54 | var ok bool 55 | fd = &Field{ 56 | Name: f.Name, 57 | Len: 1, 58 | Order: tag.Order, 59 | Slice: false, 60 | kind: f.Type.Kind(), 61 | } 62 | switch fd.kind { 63 | case reflect.Array: 64 | fd.Slice = true 65 | fd.Array = true 66 | fd.Len = f.Type.Len() 67 | fd.kind = f.Type.Elem().Kind() 68 | case reflect.Slice: 69 | fd.Slice = true 70 | fd.Len = -1 71 | fd.kind = f.Type.Elem().Kind() 72 | case reflect.Ptr: 73 | fd.Ptr = true 74 | fd.kind = f.Type.Elem().Kind() 75 | } 76 | // check for custom types 77 | tmp := reflect.New(f.Type) 78 | if _, ok := tmp.Interface().(Custom); ok { 79 | fd.Type = CustomType 80 | return 81 | } 82 | var defTypeOk bool 83 | fd.defType, defTypeOk = reflectTypeMap[fd.kind] 84 | // find a type in the struct tag 85 | pureType := typeLenRe.ReplaceAllLiteralString(tag.Type, "") 86 | if fd.Type, ok = typeLookup[pureType]; ok { 87 | fd.Len = 1 88 | match := typeLenRe.FindAllStringSubmatch(tag.Type, -1) 89 | if len(match) > 0 && len(match[0]) > 1 { 90 | fd.Slice = true 91 | first := match[0][1] 92 | // Field.Len = -1 indicates a []slice 93 | if first == "" { 94 | fd.Len = -1 95 | } else { 96 | fd.Len, err = strconv.Atoi(first) 97 | } 98 | } 99 | return 100 | } 101 | // the user didn't specify a type 102 | switch f.Type { 103 | case reflect.TypeOf(Size_t(0)): 104 | fd.Type = SizeType 105 | case reflect.TypeOf(Off_t(0)): 106 | fd.Type = OffType 107 | default: 108 | if defTypeOk { 109 | fd.Type = fd.defType 110 | } else { 111 | err = errors.New("struc: Could not find field type.") 112 | } 113 | } 114 | return 115 | } 116 | 117 | func parseFieldsLocked(v reflect.Value) (Fields, error) { 118 | // we need to repeat this logic because parseFields() below can't be recursively called due to locking 119 | for v.Kind() == reflect.Ptr { 120 | v = v.Elem() 121 | } 122 | t := v.Type() 123 | if v.NumField() < 1 { 124 | return nil, errors.New("struc: Struct has no fields.") 125 | } 126 | sizeofMap := make(map[string][]int) 127 | fields := make(Fields, 0, v.NumField()) 128 | for i := 0; i < t.NumField(); i++ { 129 | field := t.Field(i) 130 | f, err := parseField(field) 131 | if err != nil { 132 | return nil, err 133 | } 134 | f.CanSet = v.Field(i).CanSet() 135 | if !f.CanSet { 136 | continue 137 | } 138 | f.Index = i 139 | tag := parseStrucTag(field.Tag) 140 | if tag.Sizeof != "" { 141 | target, ok := t.FieldByName(tag.Sizeof) 142 | if !ok { 143 | return nil, fmt.Errorf("struc: `sizeof=%s` field does not exist", tag.Sizeof) 144 | } 145 | f.Sizeof = target.Index 146 | sizeofMap[tag.Sizeof] = field.Index 147 | } 148 | if sizefrom, ok := sizeofMap[field.Name]; ok { 149 | f.Sizefrom = sizefrom 150 | } 151 | if f.Len == -1 && f.Sizefrom == nil { 152 | return nil, fmt.Errorf("struc: field `%s` is a slice with no length or sizeof field", field.Name) 153 | } 154 | // recurse into nested structs 155 | // TODO: handle loops (probably by indirecting the []Field and putting pointer in cache) 156 | if f.Type == Struct { 157 | typ := field.Type 158 | if f.Ptr { 159 | typ = typ.Elem() 160 | } 161 | if f.Slice { 162 | typ = typ.Elem() 163 | } 164 | f.Fields, err = parseFieldsLocked(reflect.New(typ)) 165 | if err != nil { 166 | return nil, err 167 | } 168 | } 169 | fields = append(fields, f) 170 | } 171 | return fields, nil 172 | } 173 | 174 | var fieldCache = make(map[reflect.Type]Fields) 175 | var fieldCacheLock sync.RWMutex 176 | var parseLock sync.Mutex 177 | 178 | func fieldCacheLookup(t reflect.Type) Fields { 179 | fieldCacheLock.RLock() 180 | defer fieldCacheLock.RUnlock() 181 | if cached, ok := fieldCache[t]; ok { 182 | return cached 183 | } 184 | return nil 185 | } 186 | 187 | func parseFields(v reflect.Value) (Fields, error) { 188 | for v.Kind() == reflect.Ptr { 189 | v = v.Elem() 190 | } 191 | t := v.Type() 192 | 193 | // fast path: hopefully the field parsing is already cached 194 | if cached := fieldCacheLookup(t); cached != nil { 195 | return cached, nil 196 | } 197 | 198 | // hold a global lock so multiple goroutines can't parse (the same) fields at once 199 | parseLock.Lock() 200 | defer parseLock.Unlock() 201 | 202 | // check cache a second time, in case parseLock was just released by 203 | // another thread who filled the cache for us 204 | if cached := fieldCacheLookup(t); cached != nil { 205 | return cached, nil 206 | } 207 | 208 | // no luck, time to parse and fill the cache ourselves 209 | fields, err := parseFieldsLocked(v) 210 | if err != nil { 211 | return nil, err 212 | } 213 | fieldCacheLock.Lock() 214 | fieldCache[t] = fields 215 | fieldCacheLock.Unlock() 216 | return fields, nil 217 | } 218 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/parse_test.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "bytes" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | func parseTest(data interface{}) error { 10 | _, err := parseFields(reflect.ValueOf(data)) 11 | return err 12 | } 13 | 14 | type empty struct{} 15 | 16 | func TestEmptyStruc(t *testing.T) { 17 | if err := parseTest(&empty{}); err == nil { 18 | t.Fatal("failed to error on empty struct") 19 | } 20 | } 21 | 22 | type chanStruct struct { 23 | Test chan int 24 | } 25 | 26 | func TestChanError(t *testing.T) { 27 | if err := parseTest(&chanStruct{}); err == nil { 28 | // TODO: should probably ignore channel fields 29 | t.Fatal("failed to error on struct containing channel") 30 | } 31 | } 32 | 33 | type badSizeof struct { 34 | Size int `struc:"sizeof=Bad"` 35 | } 36 | 37 | func TestBadSizeof(t *testing.T) { 38 | if err := parseTest(&badSizeof{}); err == nil { 39 | t.Fatal("failed to error on missing Sizeof target") 40 | } 41 | } 42 | 43 | type missingSize struct { 44 | Test []byte 45 | } 46 | 47 | func TestMissingSize(t *testing.T) { 48 | if err := parseTest(&missingSize{}); err == nil { 49 | t.Fatal("failed to error on missing field size") 50 | } 51 | } 52 | 53 | type badNested struct { 54 | Empty empty 55 | } 56 | 57 | func TestNestedParseError(t *testing.T) { 58 | var buf bytes.Buffer 59 | if err := Pack(&buf, &badNested{}); err == nil { 60 | t.Fatal("failed to error on bad nested struct") 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/struc.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "io" 7 | "reflect" 8 | ) 9 | 10 | type Options struct { 11 | ByteAlign int 12 | PtrSize int 13 | Order binary.ByteOrder 14 | } 15 | 16 | func (o *Options) Validate() error { 17 | if o.PtrSize == 0 { 18 | o.PtrSize = 32 19 | } else { 20 | switch o.PtrSize { 21 | case 8, 16, 32, 64: 22 | default: 23 | return fmt.Errorf("Invalid Options.PtrSize: %d. Must be in (8, 16, 32, 64)", o.PtrSize) 24 | } 25 | } 26 | return nil 27 | } 28 | 29 | var emptyOptions = &Options{} 30 | 31 | func prep(data interface{}) (reflect.Value, Packer, error) { 32 | value := reflect.ValueOf(data) 33 | for value.Kind() == reflect.Ptr { 34 | next := value.Elem().Kind() 35 | if next == reflect.Struct || next == reflect.Ptr { 36 | value = value.Elem() 37 | } else { 38 | break 39 | } 40 | } 41 | switch value.Kind() { 42 | case reflect.Struct: 43 | fields, err := parseFields(value) 44 | return value, fields, err 45 | default: 46 | if !value.IsValid() { 47 | return reflect.Value{}, nil, fmt.Errorf("Invalid reflect.Value for %+v", data) 48 | } 49 | if c, ok := data.(Custom); ok { 50 | return value, customFallback{c}, nil 51 | } 52 | return value, binaryFallback(value), nil 53 | } 54 | } 55 | 56 | func Pack(w io.Writer, data interface{}) error { 57 | return PackWithOptions(w, data, nil) 58 | } 59 | 60 | func PackWithOptions(w io.Writer, data interface{}, options *Options) error { 61 | if options == nil { 62 | options = emptyOptions 63 | } 64 | if err := options.Validate(); err != nil { 65 | return err 66 | } 67 | val, packer, err := prep(data) 68 | if err != nil { 69 | return err 70 | } 71 | if val.Type().Kind() == reflect.String { 72 | val = val.Convert(reflect.TypeOf([]byte{})) 73 | } 74 | size := packer.Sizeof(val, options) 75 | buf := make([]byte, size) 76 | if _, err := packer.Pack(buf, val, options); err != nil { 77 | return err 78 | } 79 | _, err = w.Write(buf) 80 | return err 81 | } 82 | 83 | func Unpack(r io.Reader, data interface{}) error { 84 | return UnpackWithOptions(r, data, nil) 85 | } 86 | 87 | func UnpackWithOptions(r io.Reader, data interface{}, options *Options) error { 88 | if options == nil { 89 | options = emptyOptions 90 | } 91 | if err := options.Validate(); err != nil { 92 | return err 93 | } 94 | val, packer, err := prep(data) 95 | if err != nil { 96 | return err 97 | } 98 | return packer.Unpack(r, val, options) 99 | } 100 | 101 | func Sizeof(data interface{}) (int, error) { 102 | return SizeofWithOptions(data, nil) 103 | } 104 | 105 | func SizeofWithOptions(data interface{}, options *Options) (int, error) { 106 | if options == nil { 107 | options = emptyOptions 108 | } 109 | if err := options.Validate(); err != nil { 110 | return 0, err 111 | } 112 | val, packer, err := prep(data) 113 | if err != nil { 114 | return 0, err 115 | } 116 | return packer.Sizeof(val, options), nil 117 | } 118 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/struc_test.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "reflect" 7 | "testing" 8 | ) 9 | 10 | type Nested struct { 11 | Test2 int `struc:"int8"` 12 | } 13 | 14 | type Example struct { 15 | Pad []byte `struc:"[5]pad"` // 00 00 00 00 00 16 | I8f int `struc:"int8"` // 01 17 | I16f int `struc:"int16"` // 00 02 18 | I32f int `struc:"int32"` // 00 00 00 03 19 | I64f int `struc:"int64"` // 00 00 00 00 00 00 00 04 20 | U8f int `struc:"uint8,little"` // 05 21 | U16f int `struc:"uint16,little"` // 06 00 22 | U32f int `struc:"uint32,little"` // 07 00 00 00 23 | U64f int `struc:"uint64,little"` // 08 00 00 00 00 00 00 00 24 | Boolf int `struc:"bool"` // 01 25 | Byte4f []byte `struc:"[4]byte"` // "abcd" 26 | 27 | I8 int8 // 09 28 | I16 int16 // 00 0a 29 | I32 int32 // 00 00 00 0b 30 | I64 int64 // 00 00 00 00 00 00 00 0c 31 | U8 uint8 `struc:"little"` // 0d 32 | U16 uint16 `struc:"little"` // 0e 00 33 | U32 uint32 `struc:"little"` // 0f 00 00 00 34 | U64 uint64 `struc:"little"` // 10 00 00 00 00 00 00 00 35 | BoolT bool // 01 36 | BoolF bool // 00 37 | Byte4 [4]byte // "efgh" 38 | Float1 float32 // 41 a0 00 00 39 | Float2 float64 // 41 35 00 00 00 00 00 00 40 | 41 | Size int `struc:"sizeof=Str,little"` // 0a 00 00 00 42 | Str string `struc:"[]byte"` // "ijklmnopqr" 43 | Strb string `struc:"[4]byte"` // "stuv" 44 | 45 | Size2 int `struc:"uint8,sizeof=Str2"` // 04 46 | Str2 string // "1234" 47 | 48 | Size3 int `struc:"uint8,sizeof=Bstr"` // 04 49 | Bstr []byte // "5678" 50 | 51 | Nested Nested // 00 00 00 01 52 | NestedP *Nested // 00 00 00 02 53 | TestP64 *int `struc:"int64"` // 00 00 00 05 54 | 55 | NestedSize int `struc:"sizeof=NestedA"` // 00 00 00 02 56 | NestedA []Nested // [00 00 00 03, 00 00 00 04] 57 | 58 | CustomTypeSize Int3 `struc:"sizeof=CustomTypeSizeArr"` // 00 00 00 04 59 | CustomTypeSizeArr []byte // "ABCD" 60 | } 61 | 62 | var five = 5 63 | 64 | var reference = &Example{ 65 | nil, 66 | 1, 2, 3, 4, 5, 6, 7, 8, 0, []byte{'a', 'b', 'c', 'd'}, 67 | 9, 10, 11, 12, 13, 14, 15, 16, true, false, [4]byte{'e', 'f', 'g', 'h'}, 68 | 20, 21, 69 | 10, "ijklmnopqr", "stuv", 70 | 4, "1234", 71 | 4, []byte("5678"), 72 | Nested{1}, &Nested{2}, &five, 73 | 6, []Nested{{3}, {4}, {5}, {6}, {7}, {8}}, 74 | Int3(4), []byte("ABCD"), 75 | } 76 | 77 | var referenceBytes = []byte{ 78 | 0, 0, 0, 0, 0, // pad(5) 79 | 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, // fake int8-int64(1-4) 80 | 5, 6, 0, 7, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, // fake little-endian uint8-uint64(5-8) 81 | 0, // fake bool(0) 82 | 'a', 'b', 'c', 'd', // fake [4]byte 83 | 84 | 9, 0, 10, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 12, // real int8-int64(9-12) 85 | 13, 14, 0, 15, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, // real little-endian uint8-uint64(13-16) 86 | 1, 0, // real bool(1), bool(0) 87 | 'e', 'f', 'g', 'h', // real [4]byte 88 | 65, 160, 0, 0, // real float32(20) 89 | 64, 53, 0, 0, 0, 0, 0, 0, // real float64(21) 90 | 91 | 10, 0, 0, 0, // little-endian int32(10) sizeof=Str 92 | 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', // Str 93 | 's', 't', 'u', 'v', // fake string([4]byte) 94 | 04, '1', '2', '3', '4', // real string 95 | 04, '5', '6', '7', '8', // fake []byte(string) 96 | 97 | 1, 2, // Nested{1}, Nested{2} 98 | 0, 0, 0, 0, 0, 0, 0, 5, // &five 99 | 100 | 0, 0, 0, 6, // int32(6) 101 | 3, 4, 5, 6, 7, 8, // [Nested{3}, ...Nested{8}] 102 | 103 | 0, 0, 4, 'A', 'B', 'C', 'D', // Int3(4), []byte("ABCD") 104 | } 105 | 106 | func TestCodec(t *testing.T) { 107 | var buf bytes.Buffer 108 | if err := Pack(&buf, reference); err != nil { 109 | t.Fatal(err) 110 | } 111 | out := &Example{} 112 | if err := Unpack(&buf, out); err != nil { 113 | t.Fatal(err) 114 | } 115 | if !reflect.DeepEqual(reference, out) { 116 | t.Fatal("encode/decode failed") 117 | } 118 | } 119 | 120 | func TestEncode(t *testing.T) { 121 | var buf bytes.Buffer 122 | if err := Pack(&buf, reference); err != nil { 123 | t.Fatal(err) 124 | } 125 | if !bytes.Equal(buf.Bytes(), referenceBytes) { 126 | t.Fatal("encode failed") 127 | } 128 | } 129 | 130 | func TestDecode(t *testing.T) { 131 | buf := bytes.NewReader(referenceBytes) 132 | out := &Example{} 133 | if err := Unpack(buf, out); err != nil { 134 | t.Fatal(err) 135 | } 136 | if !reflect.DeepEqual(reference, out) { 137 | t.Fatal("decode failed") 138 | } 139 | } 140 | 141 | func TestSizeof(t *testing.T) { 142 | size, err := Sizeof(reference) 143 | if err != nil { 144 | t.Fatal(err) 145 | } 146 | if size != len(referenceBytes) { 147 | t.Fatal("sizeof failed") 148 | } 149 | } 150 | 151 | type ExampleEndian struct { 152 | T int `struc:"int16,big"` 153 | } 154 | 155 | func TestEndianSwap(t *testing.T) { 156 | var buf bytes.Buffer 157 | big := &ExampleEndian{1} 158 | if err := PackWithOrder(&buf, big, binary.BigEndian); err != nil { 159 | t.Fatal(err) 160 | } 161 | little := &ExampleEndian{} 162 | if err := UnpackWithOrder(&buf, little, binary.LittleEndian); err != nil { 163 | t.Fatal(err) 164 | } 165 | if little.T != 256 { 166 | t.Fatal("big -> little conversion failed") 167 | } 168 | } 169 | 170 | func TestNilValue(t *testing.T) { 171 | var buf bytes.Buffer 172 | if err := Pack(&buf, nil); err == nil { 173 | t.Fatal("failed throw error for bad struct value") 174 | } 175 | if err := Unpack(&buf, nil); err == nil { 176 | t.Fatal("failed throw error for bad struct value") 177 | } 178 | if _, err := Sizeof(nil); err == nil { 179 | t.Fatal("failed to throw error for bad struct value") 180 | } 181 | } 182 | 183 | type sliceUnderrun struct { 184 | Str string `struc:"[10]byte"` 185 | Arr []uint16 `struc:"[10]uint16"` 186 | } 187 | 188 | func TestSliceUnderrun(t *testing.T) { 189 | var buf bytes.Buffer 190 | v := sliceUnderrun{ 191 | Str: "foo", 192 | Arr: []uint16{1, 2, 3}, 193 | } 194 | if err := Pack(&buf, &v); err != nil { 195 | t.Fatal(err) 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/types.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type Type int 9 | 10 | const ( 11 | Invalid Type = iota 12 | Pad 13 | Bool 14 | Int 15 | Int8 16 | Uint8 17 | Int16 18 | Uint16 19 | Int32 20 | Uint32 21 | Int64 22 | Uint64 23 | Float32 24 | Float64 25 | String 26 | Struct 27 | Ptr 28 | 29 | SizeType 30 | OffType 31 | CustomType 32 | ) 33 | 34 | func (t Type) Resolve(options *Options) Type { 35 | switch t { 36 | case OffType: 37 | switch options.PtrSize { 38 | case 8: 39 | return Int8 40 | case 16: 41 | return Int16 42 | case 32: 43 | return Int32 44 | case 64: 45 | return Int64 46 | default: 47 | panic(fmt.Sprintf("unsupported ptr bits: %d", options.PtrSize)) 48 | } 49 | case SizeType: 50 | switch options.PtrSize { 51 | case 8: 52 | return Uint8 53 | case 16: 54 | return Uint16 55 | case 32: 56 | return Uint32 57 | case 64: 58 | return Uint64 59 | default: 60 | panic(fmt.Sprintf("unsupported ptr bits: %d", options.PtrSize)) 61 | } 62 | } 63 | return t 64 | } 65 | 66 | func (t Type) String() string { 67 | return typeNames[t] 68 | } 69 | 70 | func (t Type) Size() int { 71 | switch t { 72 | case SizeType, OffType: 73 | panic("Size_t/Off_t types must be converted to another type using options.PtrSize") 74 | case Pad, String, Int8, Uint8, Bool: 75 | return 1 76 | case Int16, Uint16: 77 | return 2 78 | case Int32, Uint32, Float32: 79 | return 4 80 | case Int64, Uint64, Float64: 81 | return 8 82 | default: 83 | panic("Cannot resolve size of type:" + t.String()) 84 | } 85 | } 86 | 87 | var typeLookup = map[string]Type{ 88 | "pad": Pad, 89 | "bool": Bool, 90 | "byte": Uint8, 91 | "int8": Int8, 92 | "uint8": Uint8, 93 | "int16": Int16, 94 | "uint16": Uint16, 95 | "int32": Int32, 96 | "uint32": Uint32, 97 | "int64": Int64, 98 | "uint64": Uint64, 99 | "float32": Float32, 100 | "float64": Float64, 101 | 102 | "size_t": SizeType, 103 | "off_t": OffType, 104 | } 105 | 106 | var typeNames = map[Type]string{ 107 | CustomType: "Custom", 108 | } 109 | 110 | func init() { 111 | for name, enum := range typeLookup { 112 | typeNames[enum] = name 113 | } 114 | } 115 | 116 | type Size_t uint64 117 | type Off_t int64 118 | 119 | var reflectTypeMap = map[reflect.Kind]Type{ 120 | reflect.Bool: Bool, 121 | reflect.Int8: Int8, 122 | reflect.Int16: Int16, 123 | reflect.Int: Int32, 124 | reflect.Int32: Int32, 125 | reflect.Int64: Int64, 126 | reflect.Uint8: Uint8, 127 | reflect.Uint16: Uint16, 128 | reflect.Uint: Uint32, 129 | reflect.Uint32: Uint32, 130 | reflect.Uint64: Uint64, 131 | reflect.Float32: Float32, 132 | reflect.Float64: Float64, 133 | reflect.String: String, 134 | reflect.Struct: Struct, 135 | reflect.Ptr: Ptr, 136 | } 137 | -------------------------------------------------------------------------------- /vendor/github.com/lunixbochs/struc/types_test.go: -------------------------------------------------------------------------------- 1 | package struc 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | func TestBadType(t *testing.T) { 9 | defer func() { recover() }() 10 | Type(-1).Size() 11 | t.Fatal("failed to panic for invalid Type.Size()") 12 | } 13 | 14 | func TestTypeString(t *testing.T) { 15 | if Pad.String() != "pad" { 16 | t.Fatal("type string representation failed") 17 | } 18 | } 19 | 20 | type sizeOffTest struct { 21 | Size Size_t 22 | Off Off_t 23 | } 24 | 25 | func TestSizeOffTypes(t *testing.T) { 26 | bits := []int{8, 16, 32, 64} 27 | var buf bytes.Buffer 28 | test := &sizeOffTest{1, 2} 29 | for _, b := range bits { 30 | if err := PackWithOptions(&buf, test, &Options{PtrSize: b}); err != nil { 31 | t.Fatal(err) 32 | } 33 | } 34 | reference := []byte{ 35 | 1, 2, 36 | 0, 1, 0, 2, 37 | 0, 0, 0, 1, 0, 0, 0, 2, 38 | 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 39 | } 40 | if !bytes.Equal(reference, buf.Bytes()) { 41 | t.Errorf("reference != bytes: %v", reference, buf.Bytes()) 42 | } 43 | reader := bytes.NewReader(buf.Bytes()) 44 | for _, b := range bits { 45 | out := &sizeOffTest{} 46 | if err := UnpackWithOptions(reader, out, &Options{PtrSize: b}); err != nil { 47 | t.Fatal(err) 48 | } 49 | if out.Size != 1 || out.Off != 2 { 50 | t.Errorf("Size_t/Off_t mismatch: {%d, %d}\n%v", out.Size, out.Off, buf.Bytes()) 51 | } 52 | } 53 | } 54 | --------------------------------------------------------------------------------