├── .gitignore ├── LICENSE ├── README.md ├── ciscoasa ├── access_in_rules.go ├── access_out_rules.go ├── ciscoasa.go ├── ciscoasa_test.go ├── dhcp.go ├── dhcp_relay_globalsettings.go ├── dhcp_relay_local.go ├── dhcp_servers.go ├── failover.go ├── failover_interfaces.go ├── failover_setup.go ├── interfaces.go ├── interfaces_physical.go ├── interfaces_vlan.go ├── licensing.go ├── nat.go ├── ntp.go ├── objects.go ├── objects_extendedacls.go ├── objects_networkobjectgroups.go ├── objects_networkobjectgroups_test.go ├── objects_networkobjects.go ├── objects_networkobjects_test.go ├── objects_networkservicegroups.go ├── objects_networkservicegroups_test.go ├── objects_networkservices.go ├── objects_timeranges.go ├── routing.go ├── save.go └── service_type.go └── go.mod /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | .idea 10 | 11 | # Architecture specific extensions/prefixes 12 | *.[568vq] 13 | [568vq].out 14 | 15 | *.cgo1.go 16 | *.cgo2.c 17 | _cgo_defun.c 18 | _cgo_gotypes.go 19 | _cgo_export.* 20 | 21 | _testmain.go 22 | 23 | *.exe 24 | *.test 25 | *.prof 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-ciscoasa 2 | A Cisco ASA API client enabling Go programs to interact with a Cisco ASA in a simple and uniform way 3 | -------------------------------------------------------------------------------- /ciscoasa/access_in_rules.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2017, Rutger te Nijenhuis & Sander van Harmelen 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | package ciscoasa 18 | 19 | import "fmt" 20 | 21 | type accessService struct { 22 | *Client 23 | } 24 | 25 | // ListAccessInRules returns a collection of access control element objects. 26 | func (s *accessService) ListAccessInRules(iface string) (*ExtendedACEObjectCollection, error) { 27 | result := &ExtendedACEObjectCollection{} 28 | page := 0 29 | 30 | for { 31 | offset := page * s.pageLimit 32 | u := fmt.Sprintf("/api/access/in/%s/rules?limit=%d&offset=%d", iface, s.pageLimit, offset) 33 | 34 | req, err := s.newRequest("GET", u, nil) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | e := &ExtendedACEObjectCollection{} 40 | _, err = s.do(req, e) 41 | if err != nil { 42 | return nil, err 43 | } 44 | 45 | result.RangeInfo = e.RangeInfo 46 | result.Items = append(result.Items, e.Items...) 47 | result.Kind = e.Kind 48 | result.SelfLink = e.SelfLink 49 | 50 | if e.RangeInfo.Offset+e.RangeInfo.Limit == e.RangeInfo.Total { 51 | break 52 | } 53 | page++ 54 | } 55 | 56 | return result, nil 57 | } 58 | 59 | // CreateAccessInRule creates an access control element. 60 | func (s *accessService) CreateAccessInRule(iface, src, srcService, dst, dstService, timeRange string, active, permit bool) (string, error) { 61 | u := fmt.Sprintf("/api/access/in/%s/rules", iface) 62 | 63 | e := &ExtendedACEObject{ 64 | Active: active, 65 | Permit: permit, 66 | Kind: "object#ExtendedACE", 67 | } 68 | 69 | var err error 70 | if e.SrcAddress, err = s.Objects.objectFromAddress(src); err != nil { 71 | return "", err 72 | } 73 | if e.SrcService, err = s.Objects.objectFromService(srcService); err != nil { 74 | return "", err 75 | } 76 | if e.DstAddress, err = s.Objects.objectFromAddress(dst); err != nil { 77 | return "", err 78 | } 79 | if e.DstService, err = s.Objects.objectFromService(dstService); err != nil { 80 | return "", err 81 | } 82 | 83 | if timeRange != "" { 84 | t := &TimeRange{ 85 | ObjectID: timeRange, 86 | Kind: "objectRef#TimeRange", 87 | } 88 | e.TimeRange = t 89 | } 90 | 91 | req, err := s.newRequest("POST", u, e) 92 | if err != nil { 93 | return "", err 94 | } 95 | 96 | resp, err := s.do(req, nil) 97 | if err != nil { 98 | return "", err 99 | } 100 | 101 | return idFromResponse(resp) 102 | } 103 | 104 | // GetAccessInRule retrieves an access control element. 105 | func (s *accessService) GetAccessInRule(iface string, ruleID string) (*ExtendedACEObject, error) { 106 | u := fmt.Sprintf("/api/access/in/%s/rules/%s", iface, ruleID) 107 | 108 | req, err := s.newRequest("GET", u, nil) 109 | if err != nil { 110 | return nil, err 111 | } 112 | 113 | e := &ExtendedACEObject{} 114 | _, err = s.do(req, e) 115 | 116 | return e, err 117 | } 118 | 119 | // UpdateAccessInRule updates an access control element. 120 | func (s *accessService) UpdateAccessInRule(iface, ruleID, src, srcService, dst, dstService, timeRange string, active, permit bool) (string, error) { 121 | u := fmt.Sprintf("/api/access/in/%s/rules/%s", iface, ruleID) 122 | 123 | e := &ExtendedACEObject{ 124 | Active: active, 125 | Permit: permit, 126 | Kind: "object#ExtendedACE", 127 | } 128 | 129 | var err error 130 | if e.SrcAddress, err = s.Objects.objectFromAddress(src); err != nil { 131 | return "", err 132 | } 133 | if e.SrcService, err = s.Objects.objectFromService(srcService); err != nil { 134 | return "", err 135 | } 136 | if e.DstAddress, err = s.Objects.objectFromAddress(dst); err != nil { 137 | return "", err 138 | } 139 | if e.DstService, err = s.Objects.objectFromService(dstService); err != nil { 140 | return "", err 141 | } 142 | 143 | if timeRange != "" { 144 | t := &TimeRange{ 145 | ObjectID: timeRange, 146 | Kind: "objectRef#TimeRange", 147 | } 148 | e.TimeRange = t 149 | } 150 | 151 | req, err := s.newRequest("PUT", u, e) 152 | if err != nil { 153 | return "", err 154 | } 155 | 156 | resp, err := s.do(req, nil) 157 | if err != nil { 158 | return "", err 159 | } 160 | 161 | return idFromResponse(resp) 162 | } 163 | 164 | // DeleteAccessInRule deletes an access control element. 165 | func (s *accessService) DeleteAccessInRule(iface string, ruleID string) error { 166 | u := fmt.Sprintf("/api/access/in/%s/rules/%s", iface, ruleID) 167 | 168 | req, err := s.newRequest("DELETE", u, nil) 169 | if err != nil { 170 | return err 171 | } 172 | 173 | _, err = s.do(req, nil) 174 | 175 | return err 176 | } 177 | -------------------------------------------------------------------------------- /ciscoasa/access_out_rules.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2017, Rutger te Nijenhuis & Sander van Harmelen 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | package ciscoasa 18 | 19 | import "fmt" 20 | 21 | // ListAccessOutRules returns a collection of access control element objects. 22 | func (s *accessService) ListAccessOutRules(iface string) (*ExtendedACEObjectCollection, error) { 23 | result := &ExtendedACEObjectCollection{} 24 | page := 0 25 | 26 | for { 27 | offset := page * s.pageLimit 28 | u := fmt.Sprintf("/api/access/out/%s/rules?limit=%d&offset=%d", iface, s.pageLimit, offset) 29 | 30 | req, err := s.newRequest("GET", u, nil) 31 | if err != nil { 32 | return nil, err 33 | } 34 | 35 | e := &ExtendedACEObjectCollection{} 36 | _, err = s.do(req, e) 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | result.RangeInfo = e.RangeInfo 42 | result.Items = append(result.Items, e.Items...) 43 | result.Kind = e.Kind 44 | result.SelfLink = e.SelfLink 45 | 46 | if e.RangeInfo.Offset+e.RangeInfo.Limit == e.RangeInfo.Total { 47 | break 48 | } 49 | page++ 50 | } 51 | 52 | return result, nil 53 | } 54 | 55 | // CreateAccessOutRule creates an access control element. 56 | func (s *accessService) CreateAccessOutRule(iface, src, srcService, dst, dstService, timeRange string, active, permit bool) (string, error) { 57 | u := fmt.Sprintf("/api/access/out/%s/rules", iface) 58 | 59 | e := &ExtendedACEObject{ 60 | Active: active, 61 | Permit: permit, 62 | Kind: "object#ExtendedACE", 63 | } 64 | 65 | var err error 66 | if e.SrcAddress, err = s.Objects.objectFromAddress(src); err != nil { 67 | return "", err 68 | } 69 | if e.SrcService, err = s.Objects.objectFromService(srcService); err != nil { 70 | return "", err 71 | } 72 | if e.DstAddress, err = s.Objects.objectFromAddress(dst); err != nil { 73 | return "", err 74 | } 75 | if e.DstService, err = s.Objects.objectFromService(dstService); err != nil { 76 | return "", err 77 | } 78 | 79 | if timeRange != "" { 80 | t := &TimeRange{ 81 | ObjectID: timeRange, 82 | Kind: "objectRef#TimeRange", 83 | } 84 | e.TimeRange = t 85 | } 86 | 87 | req, err := s.newRequest("POST", u, e) 88 | if err != nil { 89 | return "", err 90 | } 91 | 92 | resp, err := s.do(req, nil) 93 | if err != nil { 94 | return "", err 95 | } 96 | 97 | return idFromResponse(resp) 98 | } 99 | 100 | // GetAccessOutRule retrieves an access control element. 101 | func (s *accessService) GetAccessOutRule(iface string, ruleID string) (*ExtendedACEObject, error) { 102 | u := fmt.Sprintf("/api/access/out/%s/rules/%s", iface, ruleID) 103 | 104 | req, err := s.newRequest("GET", u, nil) 105 | if err != nil { 106 | return nil, err 107 | } 108 | 109 | e := &ExtendedACEObject{} 110 | _, err = s.do(req, e) 111 | 112 | return e, err 113 | } 114 | 115 | // UpdateAccessOutRule updates an access control element. 116 | func (s *accessService) UpdateAccessOutRule(iface, ruleID, src, srcService, dst, dstService, timeRange string, active, permit bool) (string, error) { 117 | u := fmt.Sprintf("/api/access/out/%s/rules/%s", iface, ruleID) 118 | 119 | e := &ExtendedACEObject{ 120 | Active: active, 121 | Permit: permit, 122 | Kind: "object#ExtendedACE", 123 | } 124 | 125 | var err error 126 | if e.SrcAddress, err = s.Objects.objectFromAddress(src); err != nil { 127 | return "", err 128 | } 129 | if e.SrcService, err = s.Objects.objectFromService(srcService); err != nil { 130 | return "", err 131 | } 132 | if e.DstAddress, err = s.Objects.objectFromAddress(dst); err != nil { 133 | return "", err 134 | } 135 | if e.DstService, err = s.Objects.objectFromService(dstService); err != nil { 136 | return "", err 137 | } 138 | 139 | if timeRange != "" { 140 | t := &TimeRange{ 141 | ObjectID: timeRange, 142 | Kind: "objectRef#TimeRange", 143 | } 144 | e.TimeRange = t 145 | } 146 | 147 | req, err := s.newRequest("PUT", u, e) 148 | if err != nil { 149 | return "", err 150 | } 151 | 152 | resp, err := s.do(req, nil) 153 | if err != nil { 154 | return "", err 155 | } 156 | 157 | return idFromResponse(resp) 158 | } 159 | 160 | // DeleteAccessOutRule deletes an access control element. 161 | func (s *accessService) DeleteAccessOutRule(iface string, ruleID string) error { 162 | u := fmt.Sprintf("/api/access/out/%s/rules/%s", iface, ruleID) 163 | 164 | req, err := s.newRequest("DELETE", u, nil) 165 | if err != nil { 166 | return err 167 | } 168 | 169 | _, err = s.do(req, nil) 170 | 171 | return err 172 | } 173 | -------------------------------------------------------------------------------- /ciscoasa/ciscoasa.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2017, Sander van Harmelen 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | package ciscoasa 18 | 19 | import ( 20 | "bytes" 21 | "crypto/tls" 22 | "encoding/json" 23 | "errors" 24 | "fmt" 25 | "io" 26 | "io/ioutil" 27 | "net" 28 | "net/http" 29 | "net/url" 30 | "strings" 31 | "time" 32 | ) 33 | 34 | // Predefine standard errors 35 | var ( 36 | ErrInternalServer = errors.New("ciscoasa: Internal Server error") 37 | ErrUnknown = errors.New("ciscoasa: Unknown error") 38 | ) 39 | 40 | // Client represents a Cisco ASA client 41 | type Client struct { 42 | client *http.Client 43 | baseURL *url.URL 44 | username string 45 | password string 46 | pageLimit int 47 | 48 | Access *accessService 49 | Interfaces *interfaceService 50 | Objects *objectsService 51 | Routing *routingService 52 | DeviceSetup *devicesetupService 53 | Dhcp *dhcpService 54 | Nat *natService 55 | Failover *failoverService 56 | Licensing *licenseService 57 | Save *saveService 58 | } 59 | 60 | // ErrorResponse represents an error response 61 | type ErrorResponse struct { 62 | Messages []*ErrorMessage `json:"messages"` 63 | } 64 | 65 | func (e *ErrorResponse) Error() string { 66 | var errs []string 67 | for _, m := range e.Messages { 68 | errs = append(errs, m.Details) 69 | } 70 | return strings.Join(errs, "\n") 71 | } 72 | 73 | // ErrorMessage represents a single API error 74 | type ErrorMessage struct { 75 | Level string `json:"level"` 76 | Code string `json:"code"` 77 | Context string `json:"context,omitempty"` 78 | Details string `json:"details"` 79 | } 80 | 81 | type protocolDefinition struct { 82 | Prefix string 83 | GroupName string 84 | Kind string 85 | } 86 | 87 | // RangeInfo common data type amongst object types 88 | type RangeInfo struct { 89 | Offset int `json:"offset"` 90 | Limit int `json:"limit"` 91 | Total int `json:"total"` 92 | } 93 | 94 | // NewClient creates a new client for communicating with a Cisco ASA 95 | func NewClient(apiURL, username, password string, sslNoVerify bool) (*Client, error) { 96 | baseURL, err := url.Parse(apiURL) 97 | if err != nil { 98 | return nil, err 99 | } 100 | 101 | c := &Client{ 102 | client: &http.Client{ 103 | Transport: &http.Transport{ 104 | Proxy: http.ProxyFromEnvironment, 105 | Dial: (&net.Dialer{ 106 | Timeout: 300 * time.Second, 107 | KeepAlive: 30 * time.Second, 108 | }).Dial, 109 | TLSClientConfig: &tls.Config{InsecureSkipVerify: sslNoVerify}, 110 | TLSHandshakeTimeout: 180 * time.Second, 111 | }, 112 | Timeout: 300 * time.Second, 113 | }, 114 | baseURL: baseURL, 115 | username: username, 116 | password: password, 117 | pageLimit: 100, 118 | } 119 | 120 | c.Access = &accessService{c} 121 | c.Interfaces = &interfaceService{c} 122 | c.Objects = &objectsService{c} 123 | c.Routing = &routingService{c} 124 | c.Save = &saveService{c} 125 | c.DeviceSetup = &devicesetupService{c} 126 | c.Dhcp = &dhcpService{c} 127 | c.Nat = &natService{c} 128 | c.Failover = &failoverService{c} 129 | c.Licensing = &licenseService{c} 130 | 131 | return c, nil 132 | } 133 | 134 | // newRequest creates a HTTP request of given method and data. 135 | func (c *Client) newRequest(method string, api string, v interface{}) (*http.Request, error) { 136 | var body io.Reader 137 | 138 | if v != nil { 139 | data, err := json.Marshal(v) 140 | if err != nil { 141 | return nil, err 142 | } 143 | 144 | body = bytes.NewReader(data) 145 | } 146 | 147 | u, err := url.Parse(api) 148 | if err != nil { 149 | return nil, err 150 | } 151 | 152 | req, err := http.NewRequest(method, c.baseURL.ResolveReference(u).String(), body) 153 | if err != nil { 154 | return nil, err 155 | } 156 | 157 | req.Close = true 158 | req.Header.Set("Content-Type", "application/json; charset=UTF-8") 159 | req.Header.Set("User-Agent", "REST API Agent") 160 | req.SetBasicAuth(c.username, c.password) 161 | 162 | return req, nil 163 | } 164 | 165 | // do makes the actual API request. 166 | func (c *Client) do(req *http.Request, v interface{}) (*http.Response, error) { 167 | resp, err := c.client.Do(req) 168 | if err != nil { 169 | return nil, err 170 | } 171 | defer resp.Body.Close() 172 | 173 | err = checkResponse(resp) 174 | if err != nil { 175 | return resp, err 176 | } 177 | 178 | if v != nil { 179 | if w, ok := v.(io.Writer); ok { 180 | _, err = io.Copy(w, resp.Body) 181 | } else { 182 | err = json.NewDecoder(resp.Body).Decode(v) 183 | } 184 | } 185 | 186 | return resp, err 187 | } 188 | 189 | // CheckResponse checks the API response for errors, and returns them if present. 190 | func checkResponse(r *http.Response) error { 191 | switch r.StatusCode { 192 | case 200, 201, 202, 204: 193 | return nil 194 | } 195 | 196 | errorResponse := &ErrorResponse{} 197 | data, err := ioutil.ReadAll(r.Body) 198 | if err == nil && data != nil { 199 | if err := json.Unmarshal(data, errorResponse); err != nil { 200 | errorResponse.Messages = append(errorResponse.Messages, &ErrorMessage{ 201 | Details: "failed to parse unknown error format", 202 | Level: "Error", 203 | }) 204 | } 205 | } 206 | 207 | return errorResponse 208 | } 209 | 210 | // kindFromValue returns the object kind of the given value. 211 | func kindFromValue(value string) (string, error) { 212 | // Test if the value references a reserved keyword. 213 | switch strings.ToLower(value) { 214 | case "any": 215 | return "AnyIPAddress", nil 216 | case "any4": 217 | return "AnyIPAddress", nil 218 | case "any6": 219 | return "AnyIPv6Address", nil 220 | } 221 | 222 | // Test if the value specifies a range. 223 | if strings.Contains(value, "-") { 224 | parts := strings.Split(value, "-") 225 | from := net.ParseIP(parts[0]) 226 | to := net.ParseIP(parts[1]) 227 | 228 | if from.To4() != nil && to.To4() != nil { 229 | return "IPv4Range", nil 230 | } 231 | if from.To16() != nil && to.To16() != nil { 232 | return "IPv6Range", nil 233 | } 234 | 235 | return "", fmt.Errorf("value is not a valid range %q", value) 236 | } 237 | 238 | // Test if the value specifies a CIDR. 239 | if strings.Contains(value, "/") { 240 | addr, _, err := net.ParseCIDR(value) 241 | if err != nil { 242 | return "", fmt.Errorf("value is not a valid CIDR: %v", err) 243 | } 244 | 245 | if addr.To4() != nil { 246 | return "IPv4Network", nil 247 | } 248 | if addr.To16() != nil { 249 | return "IPv6Network", nil 250 | } 251 | 252 | return "", fmt.Errorf("value is not a valid CIDR %q", value) 253 | } 254 | 255 | // Test if the value specifies an IP address. 256 | if addr := net.ParseIP(value); addr != nil { 257 | if addr.To4() != nil { 258 | return "IPv4Address", nil 259 | } 260 | if addr.To16() != nil { 261 | return "IPv6Address", nil 262 | } 263 | } 264 | 265 | return "", fmt.Errorf("failed to infer kind from value %q", value) 266 | } 267 | 268 | var protocolDefinitions = map[string]*protocolDefinition{ 269 | "tcp": {"tcp", "Tcp", "TcpUdpService"}, 270 | "udp": {"udp", "Udp", "TcpUdpService"}, 271 | "tcpudp": {"tcp-udp", "TcpUdp", "TcpUdpService"}, 272 | "icmp": {"icmp", "Icmp", "ICMPService"}, 273 | "icmp6": {"icmp", "Icmp6", "ICMP6Service"}, 274 | "ip": {"ip", "Ip", "IPService"}, 275 | "networkprotocol": {"networkprotocol", "Protocol", "NetworkProtocol"}, 276 | } 277 | 278 | func protocolFromValue(value string) (*protocolDefinition, error) { 279 | if p, ok := protocolDefinitions[strings.ToLower(value)]; ok { 280 | return p, nil 281 | } 282 | 283 | return nil, fmt.Errorf("protocol %q is not a known protocol", value) 284 | } 285 | 286 | func idFromResponse(resp *http.Response) (string, error) { 287 | parts := strings.Split(resp.Header.Get("Location"), "/") 288 | 289 | loc := parts[len(parts)-1] 290 | if loc == "" { 291 | return "", errors.New("failed to retrieve ID from response") 292 | } 293 | 294 | return loc, nil 295 | } 296 | 297 | // Backup represents a backup. 298 | type Backup struct { 299 | Context string `json:"context,omitempty"` 300 | Location string `json:"location"` 301 | Passphrase string `json:"passphrase,omitempty"` 302 | } 303 | 304 | // CreateBackup creates a backup. 305 | func (c *Client) CreateBackup(context, location, passphrase string) error { 306 | u := "/api/backup" 307 | 308 | r := &Backup{ 309 | Context: context, 310 | Location: location, 311 | Passphrase: passphrase, 312 | } 313 | 314 | req, err := c.newRequest("POST", u, r) 315 | if err != nil { 316 | return err 317 | } 318 | 319 | _, err = c.do(req, nil) 320 | 321 | return err 322 | } 323 | -------------------------------------------------------------------------------- /ciscoasa/ciscoasa_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2017, Rutger te Nijenhuis & Sander van Harmelen 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | package ciscoasa 18 | 19 | import ( 20 | "encoding/json" 21 | "io/ioutil" 22 | "net/http" 23 | "net/http/httptest" 24 | "reflect" 25 | "testing" 26 | ) 27 | 28 | func setup() (*http.ServeMux, *httptest.Server, *Client) { 29 | // create a HTTP multiplexer to use with the test server 30 | mux := http.NewServeMux() 31 | // server is a test HTTP server used to provide mock API responses 32 | server := httptest.NewServer(mux) 33 | // client is the CiscoASA client being tested 34 | client, _ := NewClient(server.URL, "", "", false) 35 | 36 | return mux, server, client 37 | } 38 | 39 | func teardown(server *httptest.Server) { 40 | server.Close() 41 | } 42 | 43 | func testMethod(t *testing.T, r *http.Request, want string) { 44 | if got := r.Method; got != want { 45 | t.Errorf("Request method: %s, want %s", got, want) 46 | } 47 | } 48 | 49 | type values map[string]interface{} 50 | 51 | func testJSONBody(t *testing.T, r *http.Request, want values) { 52 | b, err := ioutil.ReadAll(r.Body) 53 | if err != nil { 54 | t.Errorf("Error reading request body: %v", err) 55 | } 56 | 57 | var got values 58 | json.Unmarshal(b, &got) 59 | 60 | if !reflect.DeepEqual(got, want) { 61 | t.Errorf("Request parameters: %v, want %v", got, want) 62 | } 63 | } 64 | 65 | func TestKindFromValue(t *testing.T) { 66 | var cases = []struct { 67 | addr string 68 | kind string 69 | err bool 70 | }{ 71 | {"192.168.10.15", "IPv4Address", false}, 72 | {"192.168.10.0/24", "IPv4Network", false}, 73 | {"192.168.10.10-192.168.10.15", "IPv4Range", false}, 74 | {"FE80::0202:B3FF:FE1E:8329", "IPv6Address", false}, 75 | {"FE80::0202:B3FF:FE1E:8329/48", "IPv6Network", false}, 76 | {"FE80::0202:B3FF:FE1E:8329-FE80::0202:B3FF:FE1E:8429", "IPv6Range", false}, 77 | {"345.38.10.8", "", true}, 78 | } 79 | 80 | for _, tc := range cases { 81 | kind, err := kindFromValue(tc.addr) 82 | if tc.err != (err != nil) { 83 | t.Fatalf("kindFromValue expected error: %t, got: %v", tc.err, err) 84 | } 85 | if kind != tc.kind { 86 | t.Errorf("expected: %s, got: %s", tc.kind, kind) 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /ciscoasa/dhcp.go: -------------------------------------------------------------------------------- 1 | package ciscoasa 2 | 3 | type dhcpService struct { 4 | *Client 5 | } 6 | 7 | // DhcpServerCollection represents a collection of DHCP Relay Interface Servers. 8 | type DhcpServerCollection struct { 9 | RangeInfo RangeInfo `json:"rangeInfo"` 10 | Items []*DhcpServer `json:"items"` 11 | Kind string `json:"kind"` 12 | SelfLink string `json:"selfLink"` 13 | } 14 | 15 | // DhcpServerOptions represents a ntp server options. 16 | type DhcpServerOptions struct { 17 | Type string `json:"type"` 18 | Code int `json:"code"` 19 | Value1 string `json:"value1"` 20 | Value2 string `json:"value2,omitempty"` 21 | } 22 | 23 | // DhcpServer represents a DHCP Relay Interface Server. 24 | type DhcpServer struct { 25 | Interface *InterfaceRef `json:"interface"` 26 | Enabled bool `json:"enabled"` 27 | PoolStartIP string `json:"poolStartIP"` 28 | PoolEndIP string `json:"poolEndIP"` 29 | DnsIP1 string `json:"dnsIP1"` 30 | DnsIP2 string `json:"dnsIP2"` 31 | WinsIP1 string `json:"winsIP1"` 32 | WinsIP2 string `json:"winsIP2"` 33 | LeaseLengthInSec string `json:"leaseLengthInSec,omitempty"` 34 | PingTimeoutInMilliSec string `json:"pingTimeoutInMilliSec,omitempty"` 35 | DomainName string `json:"domainName,omitempty"` 36 | IsAutoConfigEnabled bool `json:"isAutoConfigEnabled"` 37 | AutoConfigInterface string `json:"autoConfigInterface,omitempty"` 38 | IsVpnOverride bool `json:"isVpnOverride,omitempty"` 39 | Options []*DhcpServerOptions `json:"options,omitempty"` 40 | Ddns struct { 41 | UpdateDNSClient bool `json:"updateDNSClient"` 42 | UpdateBothRecords bool `json:"updateBothRecords,omitempty"` 43 | OverrideClientSettings bool `json:"overrideClientSettings,omitempty"` 44 | } `json:"ddns"` 45 | Kind string `json:"kind"` 46 | ObjectId string `json:"objectId,omitempty"` 47 | SelfLink string `json:"selfLink,omitempty"` 48 | } 49 | 50 | // DhcpRelayLocalCollection represents a collection of DHCP Relay Interface Servers. 51 | type DhcpRelayLocalCollection struct { 52 | RangeInfo RangeInfo `json:"rangeInfo"` 53 | Items []*DhcpRelayLocal `json:"items"` 54 | Kind string `json:"kind"` 55 | SelfLink string `json:"selfLink"` 56 | } 57 | 58 | // DhcpRelayLocal represents a DHCP Relay Interface Server. 59 | type DhcpRelayLocal struct { 60 | Servers []string `json:"servers"` 61 | Interface string `json:"interface"` 62 | Kind string `json:"kind"` 63 | } 64 | 65 | // DhcpRelayGS represents a DHCP Relay Global Settings object. 66 | type DhcpRelayGS struct { 67 | Ipv4Timeout int `json:"ipv4Timeout"` 68 | Ipv6Timeout int `json:"ipv6Timeout"` 69 | TrustedOnAllInterfaces bool `json:"trustedOnAllInterfaces"` 70 | Kind string `json:"kind"` 71 | } 72 | -------------------------------------------------------------------------------- /ciscoasa/dhcp_relay_globalsettings.go: -------------------------------------------------------------------------------- 1 | package ciscoasa 2 | 3 | // UpdateDhcpRelayGlobalsettings updates a DHCP Relay Global Settings. 4 | func (s *dhcpService) UpdateDhcpRelayGlobalsettings(gs *DhcpRelayGS) error { 5 | u := "/api/dhcp/relay/servers/globalsettings" 6 | 7 | req, err := s.newRequest("PUT", u, gs) 8 | if err != nil { 9 | return err 10 | } 11 | 12 | _, err = s.do(req, nil) 13 | 14 | return err 15 | } 16 | 17 | // GetDhcpRelayGlobalsettings retrieves a DHCP Relay Global Settings. 18 | func (s *dhcpService) GetDhcpRelayGlobalsettings() (*DhcpRelayGS, error) { 19 | u := "/api/dhcp/relay/servers/globalsettings" 20 | 21 | req, err := s.newRequest("GET", u, nil) 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | r := &DhcpRelayGS{} 27 | _, err = s.do(req, r) 28 | 29 | return r, err 30 | } 31 | -------------------------------------------------------------------------------- /ciscoasa/dhcp_relay_local.go: -------------------------------------------------------------------------------- 1 | package ciscoasa 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // ListDhcpRelayLocals returns a collection of DHCP relay interface servers. 8 | func (s *dhcpService) ListDhcpRelayLocals() (*DhcpRelayLocalCollection, error) { 9 | u := "/api/dhcp/relay/servers/local" 10 | 11 | req, err := s.newRequest("GET", u, nil) 12 | if err != nil { 13 | return nil, err 14 | } 15 | 16 | r := &DhcpRelayLocalCollection{} 17 | _, err = s.do(req, r) 18 | 19 | return r, err 20 | } 21 | 22 | // CreateDhcpRelayLocal creates a DHCP relay interface server. 23 | func (s *dhcpService) CreateDhcpRelayLocal(iface string, servers []string) error { 24 | u := "/api/dhcp/relay/servers/local" 25 | 26 | r := &DhcpRelayLocal{ 27 | Interface: iface, 28 | Servers: servers, 29 | Kind: "object#DHCPRelayInterfaceServer", 30 | } 31 | 32 | req, err := s.newRequest("POST", u, r) 33 | if err != nil { 34 | return err 35 | } 36 | 37 | _, err = s.do(req, nil) 38 | 39 | return err 40 | } 41 | 42 | // GetDhcpRelayLocal retrieves a DHCP relay interface server. 43 | func (s *dhcpService) GetDhcpRelayLocal(iface string) (*DhcpRelayLocal, error) { 44 | u := fmt.Sprintf("/api/dhcp/relay/servers/local/%s", iface) 45 | 46 | req, err := s.newRequest("GET", u, nil) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | r := &DhcpRelayLocal{} 52 | _, err = s.do(req, r) 53 | 54 | return r, err 55 | } 56 | 57 | // UpdateDhcpRelayLocal updates a DHCP relay interface server. 58 | func (s *dhcpService) UpdateDhcpRelayLocal(iface string, servers []string) error { 59 | u := fmt.Sprintf("/api/dhcp/relay/servers/local/%s", iface) 60 | 61 | r := &DhcpRelayLocal{ 62 | Interface: iface, 63 | Servers: servers, 64 | Kind: "object#DHCPRelayInterfaceServer", 65 | } 66 | 67 | req, err := s.newRequest("PUT", u, r) 68 | if err != nil { 69 | return err 70 | } 71 | 72 | _, err = s.do(req, nil) 73 | 74 | return err 75 | } 76 | 77 | // DeleteDhcpRelayLocal deletes a DHCP relay interface server. 78 | func (s *dhcpService) DeleteDhcpRelayLocal(iface string) error { 79 | u := fmt.Sprintf("/api/dhcp/relay/servers/local/%s", iface) 80 | 81 | req, err := s.newRequest("DELETE", u, nil) 82 | if err != nil { 83 | return err 84 | } 85 | 86 | _, err = s.do(req, nil) 87 | 88 | return err 89 | } 90 | -------------------------------------------------------------------------------- /ciscoasa/dhcp_servers.go: -------------------------------------------------------------------------------- 1 | package ciscoasa 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // ListDhcpServers returns a collection of DHCP servers. 8 | func (s *dhcpService) ListDhcpServers() (*DhcpServerCollection, error) { 9 | u := "/api/dhcp/servers" 10 | 11 | req, err := s.newRequest("GET", u, nil) 12 | if err != nil { 13 | return nil, err 14 | } 15 | 16 | r := &DhcpServerCollection{} 17 | _, err = s.do(req, r) 18 | 19 | return r, err 20 | } 21 | 22 | // UpdateDhcpServer updates a DHCP server. 23 | func (s *dhcpService) UpdateDhcpServer(server *DhcpServer) (string, error) { 24 | u := fmt.Sprintf("/api/dhcp/servers/%s", server.ObjectId) 25 | 26 | req, err := s.newRequest("PUT", u, server) 27 | if err != nil { 28 | return "", err 29 | } 30 | 31 | resp, err := s.do(req, nil) 32 | 33 | return idFromResponse(resp) 34 | } 35 | 36 | // GetDhcpServer retrieves a DHCP server. 37 | func (s *dhcpService) GetDhcpServer(ipAddress string) (*DhcpServer, error) { 38 | u := fmt.Sprintf("/api/dhcp/servers/%s", ipAddress) 39 | 40 | req, err := s.newRequest("GET", u, nil) 41 | if err != nil { 42 | return nil, err 43 | } 44 | 45 | r := &DhcpServer{} 46 | _, err = s.do(req, r) 47 | 48 | return r, err 49 | } 50 | -------------------------------------------------------------------------------- /ciscoasa/failover.go: -------------------------------------------------------------------------------- 1 | package ciscoasa 2 | 3 | type failoverService struct { 4 | *Client 5 | } 6 | 7 | // FailoverInterfacesCollection represents a collection of Failover Interfaces. 8 | type FailoverInterfacesCollection struct { 9 | RangeInfo RangeInfo `json:"rangeInfo"` 10 | Items []*FailoverInterface `json:"items"` 11 | Kind string `json:"kind"` 12 | SelfLink string `json:"selfLink"` 13 | } 14 | 15 | // FailoverInterface represents a Failover Interface. 16 | type FailoverInterface struct { 17 | InterfaceName string `json:"interfaceName"` 18 | Name string `json:"name"` 19 | ActiveIPAddress Address `json:"activeIPAddress"` 20 | SubnetMask Address `json:"subnetMask"` 21 | StandbyIPAddress *Address `json:"standbyIPAddress,omitempty"` 22 | IsMonitored bool `json:"isMonitored"` 23 | Kind string `json:"kind"` 24 | ObjectId string `json:"objectId,omitempty"` 25 | SelfLink string `json:"selfLink,omitempty"` 26 | } 27 | 28 | // FailoverSetup represents a Failover Setup. 29 | type FailoverSetup struct { 30 | EnableFOCheck bool `json:"enableFOCheck"` 31 | SecretKey string `json:"secretKey"` 32 | IpSecKey string `json:"ipSecKey"` 33 | HexKey bool `json:"hexKey"` 34 | LanFoInterface *InterfaceRef `json:"lanFoInterface,omitempty"` 35 | LanActiveIP *Address `json:"lanActiveIP,omitempty"` 36 | LanSubnet *Address `json:"lanSubnet,omitempty"` 37 | LanStandby *Address `json:"lanStandby,omitempty"` 38 | LanIFCName string `json:"lanIFCName,omitempty"` 39 | IsLANInterfacePreferredPrimary bool `json:"isLANInterfacePreferredPrimary"` 40 | IsLANInterfacePreferredSecondary bool `json:"isLANInterfacePreferredSecondary"` 41 | StateFoInterface *InterfaceRef `json:"stateFoInterface,omitempty"` 42 | StateActiveIP *Address `json:"stateActiveIP,omitempty"` 43 | StateSubnet *Address `json:"stateSubnet,omitempty"` 44 | StateStandbyIP *Address `json:"stateStandbyIP,omitempty"` 45 | StateIFCName string `json:"stateIFCName,omitempty"` 46 | HttpReplicate bool `json:"httpReplicate"` 47 | ReplicateRate int `json:"replicateRate"` 48 | FailedInterfacesUnit string `json:"failedInterfacesUnit"` 49 | FailedInterfacesTriggeringFailover string `json:"failedInterfacesTriggeringFailover"` 50 | UnitPollTime string `json:"unitPollTime"` 51 | UnitPollTimeUnit string `json:"unitPollTimeUnit"` 52 | UnitHoldTime string `json:"unitHoldTime"` 53 | UnitHoldTimeUnit string `json:"unitHoldTimeUnit"` 54 | MonitoredPollTime string `json:"monitoredPollTime"` 55 | MonitoredPollTimeUnit string `json:"monitoredPollTimeUnit"` 56 | InterfaceHoldTime string `json:"interfaceHoldTime"` 57 | Kind string `json:"kind,omitempty"` 58 | ObjectId string `json:"objectId,omitempty"` 59 | SelfLink string `json:"selfLink,omitempty"` 60 | } 61 | -------------------------------------------------------------------------------- /ciscoasa/failover_interfaces.go: -------------------------------------------------------------------------------- 1 | package ciscoasa 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // ListFailoverInterfaces returns a collection of Failover Interfaces. 8 | func (s *failoverService) ListFailoverInterfaces() (*FailoverInterfacesCollection, error) { 9 | u := "/api/failover/interfaces" 10 | 11 | req, err := s.newRequest("GET", u, nil) 12 | if err != nil { 13 | return nil, err 14 | } 15 | 16 | r := &FailoverInterfacesCollection{} 17 | _, err = s.do(req, r) 18 | 19 | return r, err 20 | } 21 | 22 | // UpdateFailoverInterface updates a Failover Interface. 23 | func (s *failoverService) UpdateFailoverInterface(iface *FailoverInterface) error { 24 | u := fmt.Sprintf("/api/failover/interfaces/%s", iface.ObjectId) 25 | 26 | req, err := s.newRequest("PUT", u, iface) 27 | if err != nil { 28 | return err 29 | } 30 | 31 | _, err = s.do(req, nil) 32 | 33 | return err 34 | } 35 | 36 | // GetFailoverInterface retrieves a Failover Interface. 37 | func (s *failoverService) GetFailoverInterface(id string) (*FailoverInterface, error) { 38 | u := fmt.Sprintf("/api/failover/interfaces/%s", id) 39 | 40 | req, err := s.newRequest("GET", u, nil) 41 | if err != nil { 42 | return nil, err 43 | } 44 | 45 | r := &FailoverInterface{} 46 | _, err = s.do(req, r) 47 | 48 | return r, err 49 | } 50 | -------------------------------------------------------------------------------- /ciscoasa/failover_setup.go: -------------------------------------------------------------------------------- 1 | package ciscoasa 2 | 3 | var u = "/api/failover/setup" 4 | 5 | // UpdateFailoverSetup updates a Failover Setup. 6 | func (s *failoverService) UpdateFailoverSetup(setup *FailoverSetup) error { 7 | 8 | req, err := s.newRequest("PUT", u, setup) 9 | if err != nil { 10 | return err 11 | } 12 | 13 | _, err = s.do(req, nil) 14 | 15 | return err 16 | } 17 | 18 | // GetFailoverSetup retrieves a Failover Setup. 19 | func (s *failoverService) GetFailoverSetup() (*FailoverSetup, error) { 20 | 21 | req, err := s.newRequest("GET", u, nil) 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | r := &FailoverSetup{} 27 | _, err = s.do(req, r) 28 | 29 | return r, err 30 | } 31 | -------------------------------------------------------------------------------- /ciscoasa/interfaces.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2017, Rutger te Nijenhuis & Sander van Harmelen 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | package ciscoasa 18 | 19 | import ( 20 | "encoding/json" 21 | "net" 22 | "strconv" 23 | ) 24 | 25 | type interfaceService struct { 26 | *Client 27 | } 28 | 29 | type InterfaceRef struct { 30 | Kind string `json:"kind"` 31 | RefLink string `json:"refLink,omitempty"` 32 | ObjectId string `json:"objectId,omitempty"` 33 | Name string `json:"name,omitempty"` 34 | } 35 | 36 | // SlaTracking represents an SlaTracking Settings. 37 | type SlaTracking struct { 38 | SlaId int `json:"slaId"` 39 | TrackedIP string `json:"trackedIP"` 40 | FrequencyInSeconds int `json:"frequencyInSeconds"` 41 | DataSizeInBytes int `json:"dataSizeInBytes"` 42 | ThresholdInMilliseconds int `json:"thresholdInMilliseconds"` 43 | ToS int `json:"ToS"` 44 | TimeoutInMilliseconds int `json:"timeoutInMilliseconds"` 45 | NumPackets int `json:"numPackets"` 46 | } 47 | 48 | // DhcpClient represents an DHCP Settings. 49 | type DhcpClient struct { 50 | SetDefaultRoute bool `json:"setDefaultRoute"` 51 | Metric int `json:"metric"` 52 | PrimaryTrackId int `json:"primaryTrackId"` 53 | TrackingEnabled bool `json:"trackingEnabled"` 54 | SlaTrackingSettings *SlaTracking `json:"slaTrackingSettings"` 55 | } 56 | 57 | // Address represents a static IPv4/IPv6 address settings. 58 | type Address struct { 59 | Kind string `json:"kind"` 60 | Value string `json:"value"` 61 | } 62 | 63 | // IPAddress represents an IP address settings. 64 | type IPAddress struct { 65 | IP *Address `json:"ip,omitempty"` 66 | NetMask *Address `json:"netMask,omitempty"` 67 | Kind string `json:"kind"` 68 | DhcpOptionUsingMac bool `json:"dhcpOptionUsingMac,omitempty"` 69 | DhcpBroadcast bool `json:"dhcpBroadcast,omitempty"` 70 | DhcpClient *DhcpClient `json:"dhcpClient,omitempty"` 71 | } 72 | 73 | // UnmarshalJSON implements json.Unmarshaler interface. 74 | func (ip *IPAddress) UnmarshalJSON(b []byte) error { 75 | type alias IPAddress 76 | if err := json.Unmarshal(b, (*alias)(ip)); err != nil { 77 | ip = nil 78 | } 79 | return nil 80 | } 81 | 82 | func (ip *IPAddress) String() string { 83 | n := net.IPMask(net.ParseIP(ip.NetMask.Value).To4()) 84 | b, _ := n.Size() 85 | bitsize := strconv.Itoa(b) 86 | 87 | return ip.IP.Value + "/" + bitsize 88 | } 89 | 90 | // nDiscoveryPrefix represents an nDiscoveryPrefix list. 91 | type NDiscoveryPrefix struct { 92 | OffLink bool `json:"offLink"` 93 | NoAdvertise bool `json:"noAdvertise"` 94 | PreferredLifetime int `json:"preferredLifetime"` 95 | ValidLifetime int `json:"validLifetime"` 96 | HasDuration bool `json:"hasDuration"` 97 | DefaultPrefix bool `json:"defaultPrefix"` 98 | Kind string `json:"kind"` 99 | } 100 | 101 | // Ipv6Address represents an Ipv6Address. 102 | type Ipv6Address struct { 103 | PrefixLength int `json:"prefixLength,omitempty"` 104 | Standby *Address `json:"standby,omitempty"` 105 | Address *Address `json:"address,omitempty"` 106 | // IsEUI64 bool `json:"isEUI64"` 107 | Kind string `json:"kind"` 108 | } 109 | 110 | // IPv6Info represents an IPv6 address. 111 | type IPv6Info struct { 112 | Enabled bool `json:"enabled"` 113 | AutoConfig bool `json:"autoConfig"` 114 | EnforceEUI64 bool `json:"enforceEUI64"` 115 | ManagedAddressConfig bool `json:"managedAddressConfig"` 116 | NsInterval int `json:"nsInterval"` 117 | DadAttempts int `json:"dadAttempts"` 118 | NDiscoveryPrefixList []*NDiscoveryPrefix `json:"nDiscoveryPrefixList,omitempty"` 119 | OtherStatefulConfig bool `json:"otherStatefulConfig"` 120 | RouterAdvertInterval int `json:"routerAdvertInterval"` 121 | RouterAdvertIntervalUnit string `json:"routerAdvertIntervalUnit"` 122 | RouterAdvertLifetime int `json:"routerAdvertLifetime"` 123 | SuppressRouterAdvert bool `json:"suppressRouterAdvert"` 124 | ReachableTime int `json:"reachableTime"` 125 | LinkLocalAddress *Ipv6Address `json:"linkLocalAddress,omitempty"` 126 | Ipv6Addresses []*Ipv6Address `json:"ipv6Addresses,omitempty"` 127 | Kind string `json:"kind"` 128 | } 129 | 130 | // UnmarshalJSON implements json.Unmarshaler interface. 131 | func (ip *IPv6Info) UnmarshalJSON(b []byte) error { 132 | type alias IPv6Info 133 | if err := json.Unmarshal(b, (*alias)(ip)); err != nil { 134 | ip = nil 135 | } 136 | return nil 137 | } 138 | -------------------------------------------------------------------------------- /ciscoasa/interfaces_physical.go: -------------------------------------------------------------------------------- 1 | package ciscoasa 2 | 3 | import "fmt" 4 | 5 | // PhysicalInterfaceCollection represents a collection of physical interfaces. 6 | type PhysicalInterfaceCollection struct { 7 | RangeInfo RangeInfo `json:"rangeInfo"` 8 | Items []*PhysicalInterface `json:"items"` 9 | Kind string `json:"kind"` 10 | SelfLink string `json:"selfLink"` 11 | } 12 | 13 | // PhysicalInterface represents an interface. 14 | type PhysicalInterface struct { 15 | HardwareID string `json:"hardwareID"` 16 | InterfaceDesc string `json:"interfaceDesc"` 17 | ChannelGroupID string `json:"channelGroupID"` 18 | ChannelGroupMode string `json:"channelGroupMode"` 19 | Duplex string `json:"duplex,omitempty"` 20 | FlowcontrolOn bool `json:"flowcontrolOn"` 21 | FlowcontrolHigh int `json:"flowcontrolHigh"` 22 | FlowcontrolLow int `json:"flowcontrolLow"` 23 | FlowcontrolPeriod int `json:"flowcontrolPeriod"` 24 | ForwardTrafficCX bool `json:"forwardTrafficCX"` 25 | ForwardTrafficSFR bool `json:"forwardTrafficSFR"` 26 | LacpPriority int `json:"lacpPriority"` 27 | ActiveMacAddress string `json:"activeMacAddress"` 28 | StandByMacAddress string `json:"standByMacAddress"` 29 | ManagementOnly bool `json:"managementOnly"` 30 | Mtu int `json:"mtu"` 31 | Name string `json:"name"` 32 | SecurityLevel int `json:"securityLevel"` 33 | Shutdown bool `json:"shutdown"` 34 | Speed string `json:"speed,omitempty"` 35 | IPAddress *IPAddress `json:"ipAddress,omitempty"` 36 | Ipv6Info *IPv6Info `json:"ipv6Info,omitempty"` 37 | Kind string `json:"kind"` 38 | ObjectID string `json:"objectId,omitempty"` 39 | SelfLink string `json:"selfLink,omitempty"` 40 | } 41 | 42 | // ListPhysicalInterfaces returns a collection of interfaces. 43 | func (s *interfaceService) ListPhysicalInterfaces() (*PhysicalInterfaceCollection, error) { 44 | result := &PhysicalInterfaceCollection{} 45 | page := 0 46 | 47 | for { 48 | offset := page * s.pageLimit 49 | u := fmt.Sprintf("/api/interfaces/physical?limit=%d&offset=%d", s.pageLimit, offset) 50 | 51 | req, err := s.newRequest("GET", u, nil) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | e := &PhysicalInterfaceCollection{} 57 | _, err = s.do(req, e) 58 | if err != nil { 59 | return nil, err 60 | } 61 | 62 | result.RangeInfo = e.RangeInfo 63 | result.Items = append(result.Items, e.Items...) 64 | result.Kind = e.Kind 65 | result.SelfLink = e.SelfLink 66 | 67 | if e.RangeInfo.Offset+e.RangeInfo.Limit == e.RangeInfo.Total { 68 | break 69 | } 70 | page++ 71 | } 72 | 73 | return result, nil 74 | } 75 | 76 | // UpdatePhysicalInterface updates a physical interface 77 | // as there is no way of creating a physical interface. 78 | func (s *interfaceService) UpdatePhysicalInterface( 79 | activeMacAddress string, 80 | forwardTrafficCX bool, 81 | forwardTrafficSFR bool, 82 | hardwareID string, 83 | interfaceDesc string, 84 | ipAddress *IPAddress, 85 | ipv6Info *IPv6Info, 86 | kind string, 87 | managementOnly bool, 88 | mtu int, 89 | name string, 90 | objectID string, 91 | securityLevel int, 92 | shutdown bool, 93 | standByMacAddress string, 94 | ) (string, error) { 95 | u := fmt.Sprintf("/api/interfaces/physical/%s", objectID) 96 | 97 | duplex := "auto" 98 | speed := "auto" 99 | if kind == "object#TenGigInterface" { 100 | duplex = "" 101 | speed = "" 102 | } 103 | 104 | r := &PhysicalInterface{ 105 | ActiveMacAddress: activeMacAddress, 106 | ChannelGroupID: "", 107 | ChannelGroupMode: "active", 108 | Duplex: duplex, 109 | FlowcontrolHigh: -1, 110 | FlowcontrolLow: -1, 111 | FlowcontrolOn: false, 112 | FlowcontrolPeriod: -1, 113 | ForwardTrafficCX: forwardTrafficCX, 114 | ForwardTrafficSFR: forwardTrafficSFR, 115 | HardwareID: hardwareID, 116 | InterfaceDesc: interfaceDesc, 117 | IPAddress: ipAddress, 118 | Ipv6Info: ipv6Info, 119 | Kind: kind, 120 | LacpPriority: -1, 121 | ManagementOnly: managementOnly, 122 | Mtu: mtu, 123 | Name: name, 124 | SecurityLevel: securityLevel, 125 | Shutdown: shutdown, 126 | Speed: speed, 127 | StandByMacAddress: standByMacAddress, 128 | } 129 | 130 | req, err := s.newRequest("PUT", u, r) 131 | if err != nil { 132 | return "", err 133 | } 134 | 135 | resp, err := s.do(req, nil) 136 | if err != nil { 137 | return "", err 138 | } 139 | 140 | return idFromResponse(resp) 141 | } 142 | 143 | // GetPhysicalInterface retrieves a physical interface. 144 | func (s *interfaceService) GetPhysicalInterface(objectID string) (*PhysicalInterface, error) { 145 | u := fmt.Sprintf("/api/interfaces/physical/%s", objectID) 146 | 147 | req, err := s.newRequest("GET", u, nil) 148 | if err != nil { 149 | return nil, err 150 | } 151 | 152 | r := &PhysicalInterface{} 153 | _, err = s.do(req, r) 154 | 155 | return r, err 156 | } 157 | 158 | // DeletePhysicalInterface sets values to defaults 159 | // as there is no way of deletion a physical interface. 160 | func (s *interfaceService) DeletePhysicalInterface( 161 | hardwareID string, 162 | kind string, 163 | objectID string, 164 | ) error { 165 | u := fmt.Sprintf("/api/interfaces/physical/%s", objectID) 166 | 167 | duplex := "auto" 168 | speed := "auto" 169 | if kind == "object#TenGigInterface" { 170 | duplex = "" 171 | speed = "" 172 | } 173 | 174 | r := &PhysicalInterface{ 175 | ActiveMacAddress: "", 176 | ChannelGroupID: "", 177 | ChannelGroupMode: "active", 178 | Duplex: duplex, 179 | FlowcontrolHigh: -1, 180 | FlowcontrolLow: -1, 181 | FlowcontrolOn: false, 182 | FlowcontrolPeriod: -1, 183 | ForwardTrafficCX: false, 184 | ForwardTrafficSFR: false, 185 | HardwareID: hardwareID, 186 | InterfaceDesc: "", 187 | IPAddress: nil, 188 | Ipv6Info: nil, 189 | Kind: kind, 190 | LacpPriority: -1, 191 | ManagementOnly: false, 192 | Mtu: 1500, 193 | Name: "", 194 | SecurityLevel: -1, 195 | Shutdown: true, 196 | Speed: speed, 197 | StandByMacAddress: "", 198 | } 199 | 200 | req, err := s.newRequest("PUT", u, r) 201 | if err != nil { 202 | return err 203 | } 204 | 205 | resp, err := s.do(req, nil) 206 | if err != nil { 207 | return err 208 | } 209 | 210 | err = checkResponse(resp) 211 | 212 | return err 213 | 214 | } 215 | -------------------------------------------------------------------------------- /ciscoasa/interfaces_vlan.go: -------------------------------------------------------------------------------- 1 | package ciscoasa 2 | 3 | import "fmt" 4 | 5 | // VlanInterfaceCollection represents a collection of vlan interfaces. 6 | type VlanInterfaceCollection struct { 7 | RangeInfo RangeInfo `json:"rangeInfo"` 8 | Items []*VlanInterface `json:"items"` 9 | Kind string `json:"kind"` 10 | SelfLink string `json:"selfLink"` 11 | } 12 | 13 | // VlanInterface represents an vlan interface. 14 | type VlanInterface struct { 15 | HardwareID string `json:"hardwareID"` 16 | InterfaceDesc string `json:"interfaceDesc"` 17 | ForwardTrafficCX bool `json:"forwardTrafficCX"` 18 | ForwardTrafficSFR bool `json:"forwardTrafficSFR"` 19 | ActiveMacAddress string `json:"activeMacAddress"` 20 | StandByMacAddress string `json:"standByMacAddress"` 21 | ManagementOnly bool `json:"managementOnly"` 22 | Mtu int `json:"mtu"` 23 | Name string `json:"name"` 24 | SecurityLevel int `json:"securityLevel"` 25 | Shutdown bool `json:"shutdown"` 26 | VlanID int `json:"vlanID"` 27 | IPAddress *IPAddress `json:"ipAddress,omitempty"` 28 | Ipv6Info *IPv6Info `json:"ipv6Info,omitempty"` 29 | Kind string `json:"kind"` 30 | ObjectID string `json:"objectId,omitempty"` 31 | SelfLink string `json:"selfLink,omitempty"` 32 | } 33 | 34 | // ListVlanInterfaces returns a collection of interfaces. 35 | func (s *interfaceService) ListVlanInterfaces() (*VlanInterfaceCollection, error) { 36 | result := &VlanInterfaceCollection{} 37 | page := 0 38 | 39 | for { 40 | offset := page * s.pageLimit 41 | u := fmt.Sprintf("/api/interfaces/vlan?limit=%d&offset=%d", s.pageLimit, offset) 42 | 43 | req, err := s.newRequest("GET", u, nil) 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | e := &VlanInterfaceCollection{} 49 | _, err = s.do(req, e) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | result.RangeInfo = e.RangeInfo 55 | result.Items = append(result.Items, e.Items...) 56 | result.Kind = e.Kind 57 | result.SelfLink = e.SelfLink 58 | 59 | if e.RangeInfo.Offset+e.RangeInfo.Limit == e.RangeInfo.Total { 60 | break 61 | } 62 | page++ 63 | } 64 | 65 | return result, nil 66 | } 67 | 68 | // CreateVlanInterface creates a vlan interface. 69 | func (s *interfaceService) CreateVlanInterface( 70 | activeMacAddress string, 71 | forwardTrafficCX bool, 72 | forwardTrafficSFR bool, 73 | hardwareID string, 74 | interfaceDesc string, 75 | ipAddress *IPAddress, 76 | ipv6Info *IPv6Info, 77 | kind string, 78 | managementOnly bool, 79 | mtu int, 80 | name string, 81 | securityLevel int, 82 | shutdown bool, 83 | standByMacAddress string, 84 | vlanId int, 85 | ) (string, error) { 86 | u := "/api/interfaces/vlan/" 87 | 88 | r := &VlanInterface{ 89 | ActiveMacAddress: activeMacAddress, 90 | ForwardTrafficCX: forwardTrafficCX, 91 | ForwardTrafficSFR: forwardTrafficSFR, 92 | HardwareID: hardwareID, 93 | InterfaceDesc: interfaceDesc, 94 | IPAddress: ipAddress, 95 | Ipv6Info: ipv6Info, 96 | Kind: kind, 97 | ManagementOnly: managementOnly, 98 | Mtu: mtu, 99 | Name: name, 100 | SecurityLevel: securityLevel, 101 | Shutdown: shutdown, 102 | StandByMacAddress: standByMacAddress, 103 | VlanID: vlanId, 104 | } 105 | 106 | req, err := s.newRequest("POST", u, r) 107 | if err != nil { 108 | return "", err 109 | } 110 | 111 | resp, err := s.do(req, nil) 112 | if err != nil { 113 | return "", err 114 | } 115 | 116 | return idFromResponse(resp) 117 | } 118 | 119 | // UpdateVlanInterface updates a vlan interface. 120 | func (s *interfaceService) UpdateVlanInterface( 121 | activeMacAddress string, 122 | forwardTrafficCX bool, 123 | forwardTrafficSFR bool, 124 | hardwareID string, 125 | interfaceDesc string, 126 | ipAddress *IPAddress, 127 | ipv6Info *IPv6Info, 128 | kind string, 129 | managementOnly bool, 130 | mtu int, 131 | name string, 132 | objectID string, 133 | securityLevel int, 134 | shutdown bool, 135 | standByMacAddress string, 136 | vlanId int, 137 | ) error { 138 | u := fmt.Sprintf("/api/interfaces/vlan/%s", objectID) 139 | 140 | r := &VlanInterface{ 141 | ActiveMacAddress: activeMacAddress, 142 | ForwardTrafficCX: forwardTrafficCX, 143 | ForwardTrafficSFR: forwardTrafficSFR, 144 | HardwareID: hardwareID, 145 | InterfaceDesc: interfaceDesc, 146 | IPAddress: ipAddress, 147 | Ipv6Info: ipv6Info, 148 | Kind: kind, 149 | ManagementOnly: managementOnly, 150 | Mtu: mtu, 151 | Name: name, 152 | ObjectID: objectID, 153 | SecurityLevel: securityLevel, 154 | Shutdown: shutdown, 155 | StandByMacAddress: standByMacAddress, 156 | VlanID: vlanId, 157 | } 158 | 159 | req, err := s.newRequest("PUT", u, r) 160 | if err != nil { 161 | return err 162 | } 163 | 164 | resp, err := s.do(req, nil) 165 | if err != nil { 166 | return err 167 | } 168 | 169 | err = checkResponse(resp) 170 | 171 | return err 172 | } 173 | 174 | // GetVlanInterface retrieves a vlan interface. 175 | func (s *interfaceService) GetVlanInterface(objectID string) (*VlanInterface, error) { 176 | u := fmt.Sprintf("/api/interfaces/vlan/%s", objectID) 177 | 178 | req, err := s.newRequest("GET", u, nil) 179 | if err != nil { 180 | return nil, err 181 | } 182 | 183 | r := &VlanInterface{} 184 | _, err = s.do(req, r) 185 | 186 | return r, err 187 | } 188 | 189 | // DeleteVlanInterface deletes a vlan interface. 190 | func (s *interfaceService) DeleteVlanInterface(objectID string) error { 191 | u := fmt.Sprintf("/api/interfaces/vlan/%s", objectID) 192 | 193 | req, err := s.newRequest("DELETE", u, nil) 194 | if err != nil { 195 | return err 196 | } 197 | 198 | _, err = s.do(req, nil) 199 | 200 | return err 201 | } 202 | -------------------------------------------------------------------------------- /ciscoasa/licensing.go: -------------------------------------------------------------------------------- 1 | package ciscoasa 2 | 3 | type licenseService struct { 4 | *Client 5 | } 6 | 7 | type SmartLicenseConfig struct { 8 | Kind string `json:"kind,omitempty"` 9 | LicenseServerURL string `json:"licenseServerURL"` 10 | TransportURL bool `json:"transportURL"` 11 | PrivacyHostName bool `json:"privacyHostName"` 12 | PrivacyVersion bool `json:"privacyVersion"` 13 | Throughput string `json:"throughput,omitempty"` 14 | FeatureTier string `json:"featureTier,omitempty"` 15 | } 16 | 17 | // UpdateLicenseConfig updates a Smart License Config. 18 | func (s *licenseService) UpdateLicenseConfig(lic *SmartLicenseConfig) error { 19 | u := "/api/licensing/smart/asav" 20 | 21 | req, err := s.newRequest("PUT", u, lic) 22 | if err != nil { 23 | return err 24 | } 25 | 26 | _, err = s.do(req, nil) 27 | 28 | return err 29 | } 30 | 31 | // GetLicense retrieves a Smart License Config. 32 | func (s *licenseService) GetLicenseConfig() (*SmartLicenseConfig, error) { 33 | u := "/api/licensing/smart/asav" 34 | 35 | req, err := s.newRequest("GET", u, nil) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | r := &SmartLicenseConfig{} 41 | _, err = s.do(req, r) 42 | 43 | return r, err 44 | } 45 | 46 | // RegisterLicense registers the Smart License. 47 | func (c *licenseService) RegisterLicense(token string, force bool) error { 48 | u := "/api/licensing/smart/asav/register" 49 | 50 | r := struct { 51 | Kind string `json:"kind"` 52 | IdToken string `json:"idToken"` 53 | Force bool `json:"force"` 54 | }{ 55 | Kind: "object#SmartLicenseRegId", 56 | IdToken: token, 57 | Force: force, 58 | } 59 | 60 | req, err := c.newRequest("POST", u, r) 61 | if err != nil { 62 | return err 63 | } 64 | 65 | _, err = c.do(req, nil) 66 | 67 | return err 68 | } 69 | 70 | // DeregisterLicense removes the Smart License. 71 | func (c *licenseService) DeregisterLicense() error { 72 | u := "/api/licensing/smart/asav/deregister" 73 | 74 | req, err := c.newRequest("POST", u, nil) 75 | if err != nil { 76 | return err 77 | } 78 | 79 | _, err = c.do(req, nil) 80 | 81 | return err 82 | } 83 | 84 | // RenewIdLicense renews the Smart License entitlement. 85 | func (c *licenseService) RenewAuthLicense() error { 86 | u := "/api/licensing/smart/asav/renewauth" 87 | 88 | req, err := c.newRequest("POST", u, nil) 89 | if err != nil { 90 | return err 91 | } 92 | 93 | _, err = c.do(req, nil) 94 | 95 | return err 96 | } 97 | 98 | // RenewIdLicense renews the Smart License ID certificate. 99 | func (c *licenseService) RenewIdLicense() error { 100 | u := "/api/licensing/smart/asav/renewid" 101 | 102 | req, err := c.newRequest("POST", u, nil) 103 | if err != nil { 104 | return err 105 | } 106 | 107 | _, err = c.do(req, nil) 108 | 109 | return err 110 | } 111 | -------------------------------------------------------------------------------- /ciscoasa/nat.go: -------------------------------------------------------------------------------- 1 | package ciscoasa 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | type natService struct { 9 | *Client 10 | } 11 | 12 | type NatCollection struct { 13 | Items []*Nat `json:"items"` 14 | Kind string `json:"kind"` 15 | RangeInfo RangeInfo `json:"rangeInfo"` 16 | SelfLink string `json:"selfLink"` 17 | } 18 | 19 | type TranslatedOriginalObj struct { 20 | Kind string `json:"kind"` 21 | ObjectId string `json:"objectId,omitempty"` 22 | Value string `json:"value,omitempty"` 23 | } 24 | 25 | type TranslatedOriginalInterface struct { 26 | Kind string `json:"kind"` 27 | Name string `json:"name"` 28 | } 29 | 30 | type Nat struct { 31 | Active bool `json:"active"` 32 | BlockAllocation bool `json:"blockAllocation,omitempty"` 33 | Description string `json:"description,omitempty"` 34 | Extended bool `json:"extended,omitempty"` 35 | Flat bool `json:"flat,omitempty"` 36 | IncludeReserve bool `json:"includeReserve,omitempty"` 37 | IsDNS bool `json:"isDNS,omitempty"` 38 | IsInterfacePAT bool `json:"isInterfacePAT,omitempty"` 39 | IsNetToNet bool `json:"isNetToNet,omitempty"` 40 | IsNoProxyArp bool `json:"isNoProxyArp,omitempty"` 41 | IsPatPool bool `json:"isPatPool,omitempty"` 42 | IsRoundRobin bool `json:"isRoundRobin,omitempty"` 43 | IsRouteLookup bool `json:"isRouteLookup,omitempty"` 44 | IsUnidirectional bool `json:"isUnidirectional,omitempty"` 45 | Kind string `json:"kind,omitempty"` 46 | Mode string `json:"mode"` 47 | ObjectID string `json:"objectId,omitempty"` 48 | OriginalDestination *TranslatedOriginalObj `json:"originalDestination,omitempty"` 49 | OriginalInterface *TranslatedOriginalInterface `json:"originalInterface,omitempty"` 50 | OriginalService *TranslatedOriginalObj `json:"originalService,omitempty"` 51 | OriginalSource *TranslatedOriginalObj `json:"originalSource,omitempty"` 52 | Position int `json:"position,omitempty"` 53 | SelfLink string `json:"selfLink,omitempty"` 54 | TranslatedDestination *TranslatedOriginalObj `json:"translatedDestination,omitempty"` 55 | TranslatedInterface *TranslatedOriginalInterface `json:"translatedInterface,omitempty"` 56 | TranslatedService *TranslatedOriginalObj `json:"translatedService,omitempty"` 57 | TranslatedSource *TranslatedOriginalObj `json:"translatedSource,omitempty"` 58 | TranslatedSourcePatPool *TranslatedOriginalObj `json:"translatedSourcePatPool,omitempty"` 59 | UseDestinationInterfaceIPv6 bool `json:"useDestinationInterfaceIPv6,omitempty"` 60 | UseSourceInterfaceIPv6 bool `json:"useSourceInterfaceIPv6,omitempty"` 61 | } 62 | 63 | func (iface *TranslatedOriginalInterface) UnmarshalJSON(b []byte) error { 64 | type alias TranslatedOriginalInterface 65 | if err := json.Unmarshal(b, (*alias)(iface)); err != nil { 66 | iface = nil 67 | } 68 | return nil 69 | } 70 | 71 | func (translated *TranslatedOriginalObj) UnmarshalJSON(b []byte) error { 72 | type alias TranslatedOriginalObj 73 | if err := json.Unmarshal(b, (*alias)(translated)); err != nil { 74 | translated = nil 75 | } 76 | return nil 77 | } 78 | 79 | // ListNats returns a collection of NATs. 80 | func (s *natService) ListNats(section string) (*NatCollection, error) { 81 | u := fmt.Sprintf("/api/nat/%s", section) 82 | 83 | req, err := s.newRequest("GET", u, nil) 84 | if err != nil { 85 | return nil, err 86 | } 87 | 88 | r := &NatCollection{} 89 | _, err = s.do(req, r) 90 | 91 | return r, err 92 | } 93 | 94 | // CreateNat creates a NAT. 95 | func (s *natService) CreateNat(section string, nat *Nat) (string, error) { 96 | u := fmt.Sprintf("/api/nat/%s", section) 97 | 98 | req, err := s.newRequest("POST", u, nat) 99 | if err != nil { 100 | return "", err 101 | } 102 | 103 | resp, err := s.do(req, nil) 104 | if err != nil { 105 | return "", err 106 | } 107 | 108 | return idFromResponse(resp) 109 | } 110 | 111 | // GetNat retrieves a NAT. 112 | func (s *natService) GetNat(section, id string) (*Nat, error) { 113 | u := fmt.Sprintf("/api/nat/%s/%s", section, id) 114 | 115 | req, err := s.newRequest("GET", u, nil) 116 | if err != nil { 117 | return nil, err 118 | } 119 | 120 | r := &Nat{} 121 | _, err = s.do(req, r) 122 | 123 | return r, err 124 | } 125 | 126 | // UpdateNat updates a NAT. 127 | func (s *natService) UpdateNat(section, id string, nat *Nat) (string, error) { 128 | u := fmt.Sprintf("/api/nat/%s/%s", section, id) 129 | 130 | req, err := s.newRequest("PUT", u, nat) 131 | if err != nil { 132 | return "", err 133 | } 134 | 135 | resp, err := s.do(req, nil) 136 | if err != nil { 137 | return "", err 138 | } 139 | 140 | return idFromResponse(resp) 141 | } 142 | 143 | // DeleteNat deletes a NAT. 144 | func (s *natService) DeleteNat(section, id string) error { 145 | u := fmt.Sprintf("/api/nat/%s/%s", section, id) 146 | 147 | req, err := s.newRequest("DELETE", u, nil) 148 | if err != nil { 149 | return err 150 | } 151 | 152 | _, err = s.do(req, nil) 153 | 154 | return err 155 | } 156 | -------------------------------------------------------------------------------- /ciscoasa/ntp.go: -------------------------------------------------------------------------------- 1 | package ciscoasa 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type devicesetupService struct { 9 | *Client 10 | } 11 | 12 | // NtpServerObjectCollection represents a collection of ntp server objects. 13 | type NtpServerObjectCollection struct { 14 | RangeInfo RangeInfo `json:"rangeInfo"` 15 | Items []*NtpServerObject `json:"items"` 16 | Kind string `json:"kind"` 17 | SelfLink string `json:"selfLink"` 18 | } 19 | 20 | // NtpServerObject represents a ntp server object. 21 | type NtpServerObject struct { 22 | IpAddress string `json:"ipAddress"` 23 | IsPreferred bool `json:"isPreferred,omitempty"` 24 | Interface *InterfaceRef `json:"interface,omitempty"` 25 | Key struct { 26 | Number string `json:"number"` 27 | Value string `json:"value"` 28 | IsTrusted bool `json:"isTrusted,omitempty"` 29 | } `json:"key"` 30 | Kind string `json:"kind"` 31 | ObjectId string `json:"objectId,omitempty"` 32 | SelfLink string `json:"selfLink,omitempty"` 33 | } 34 | 35 | // ListNtpServers returns a collection of NTP servers. 36 | func (s *devicesetupService) ListNtpServers() (*NtpServerObjectCollection, error) { 37 | u := "/api/devicesetup/ntp/servers" 38 | 39 | req, err := s.newRequest("GET", u, nil) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | r := &NtpServerObjectCollection{} 45 | _, err = s.do(req, r) 46 | 47 | return r, err 48 | } 49 | 50 | // CreateNtpServer creates a NTP server. 51 | func (s *devicesetupService) CreateNtpServer(ipAddress string, preferred bool, iface, knumber, kvalue string, ktrusted bool) error { 52 | u := "/api/devicesetup/ntp/servers" 53 | 54 | r := &NtpServerObject{ 55 | IpAddress: ipAddress, 56 | IsPreferred: preferred, 57 | Kind: "object#NTPServer", 58 | } 59 | 60 | r.Key.Number = knumber 61 | r.Key.Value = kvalue 62 | r.Key.IsTrusted = ktrusted 63 | 64 | if iface != "" { 65 | i := &InterfaceRef{ 66 | Kind: "objectRef#Interface", 67 | } 68 | if isInterfaceObjectId(iface) { 69 | i.ObjectId = iface 70 | } else { 71 | i.Name = iface 72 | } 73 | r.Interface = i 74 | } 75 | 76 | req, err := s.newRequest("POST", u, r) 77 | if err != nil { 78 | return err 79 | } 80 | 81 | _, err = s.do(req, nil) 82 | 83 | return err 84 | } 85 | 86 | // GetNtpServer retrieves a NTP server. 87 | func (s *devicesetupService) GetNtpServer(ipAddress string) (*NtpServerObject, error) { 88 | u := fmt.Sprintf("/api/devicesetup/ntp/servers/%s", ipAddress) 89 | 90 | req, err := s.newRequest("GET", u, nil) 91 | if err != nil { 92 | return nil, err 93 | } 94 | 95 | r := &NtpServerObject{} 96 | _, err = s.do(req, r) 97 | 98 | return r, err 99 | } 100 | 101 | // UpdateNtpServer updates a NTP server. 102 | func (s *devicesetupService) UpdateNtpServer(objectId, ipAddress string, preferred bool, iface, knumber, kvalue string, ktrusted bool) error { 103 | u := fmt.Sprintf("/api/devicesetup/ntp/servers/%s", objectId) 104 | 105 | r := &NtpServerObject{ 106 | IpAddress: ipAddress, 107 | IsPreferred: preferred, 108 | Kind: "object#NTPServer", 109 | } 110 | 111 | r.Key.Number = knumber 112 | r.Key.Value = kvalue 113 | r.Key.IsTrusted = ktrusted 114 | 115 | if iface != "" { 116 | i := &InterfaceRef{ 117 | Kind: "objectRef#Interface", 118 | } 119 | if isInterfaceObjectId(iface) { 120 | i.ObjectId = iface 121 | } else { 122 | i.Name = iface 123 | } 124 | r.Interface = i 125 | } 126 | 127 | req, err := s.newRequest("PUT", u, r) 128 | if err != nil { 129 | return err 130 | } 131 | 132 | _, err = s.do(req, nil) 133 | 134 | return err 135 | } 136 | 137 | // DeleteNtpServer deletes a NTP server. 138 | func (s *devicesetupService) DeleteNtpServer(ipAddress string) error { 139 | u := fmt.Sprintf("/api/devicesetup/ntp/servers/%s", ipAddress) 140 | 141 | req, err := s.newRequest("DELETE", u, nil) 142 | if err != nil { 143 | return err 144 | } 145 | 146 | _, err = s.do(req, nil) 147 | 148 | return err 149 | } 150 | 151 | func isInterfaceObjectId(iface string) bool { 152 | return strings.Contains(iface, "_API_SLASH_") 153 | } 154 | -------------------------------------------------------------------------------- /ciscoasa/objects.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2017, Rutger te Nijenhuis & Sander van Harmelen 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | package ciscoasa 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | "regexp" 23 | "strings" 24 | ) 25 | 26 | type objectsService struct { 27 | *Client 28 | } 29 | type Periodic struct { 30 | Frequency string `json:"frequency"` 31 | StartHour int `json:"startHour"` 32 | StartMinute int `json:"startMinute"` 33 | EndHour int `json:"endHour"` 34 | EndMinute int `json:"endMinute"` 35 | } 36 | 37 | func (s *objectsService) objectFromAddress(address string) (*AddressObject, error) { 38 | if address == "" { 39 | return nil, errors.New("an address cannot be an empty string") 40 | } 41 | 42 | o := &AddressObject{} 43 | 44 | // Test if the address is referencing a network object. 45 | if n, err := s.GetNetworkObject(address); err == nil { 46 | o.Kind = strings.Replace(n.Kind, "object#", "objectRef#", 1) 47 | o.ObjectID = address 48 | return o, nil 49 | } 50 | 51 | // Test if the address is referencing a network object group. 52 | if n, err := s.GetNetworkObjectGroup(address); err == nil { 53 | o.Kind = strings.Replace(n.Kind, "object#", "objectRef#", 1) 54 | o.ObjectID = address 55 | return o, nil 56 | } 57 | 58 | // Test if the address kind can be inferred from it's value. 59 | if k, err := kindFromValue(address); err == nil { 60 | if strings.HasSuffix(o.Kind, "Range") { 61 | return nil, errors.New("an address cannot be an IP range") 62 | } 63 | o.Kind = k 64 | o.Value = address 65 | return o, nil 66 | } 67 | 68 | return nil, fmt.Errorf("failed to create object from address %q", address) 69 | } 70 | 71 | var regexpPorts = regexp.MustCompile("^[0-9]+(-[0-9]+)?") 72 | 73 | func (s *objectsService) objectFromService(service string) (*ServiceObject, error) { 74 | if service == "" { 75 | return nil, nil 76 | } 77 | 78 | o := &ServiceObject{} 79 | parts := strings.SplitN(service, "/", 2) 80 | 81 | if len(parts) == 1 { 82 | // Test if the service is referencing a network service. 83 | if n, err := s.GetNetworkService(parts[0]); err == nil { 84 | o.Kind = strings.Replace(n.Kind, "object#", "objectRef#", 1) 85 | o.ObjectID = n.ObjectID 86 | return o, nil 87 | } 88 | 89 | // Test is the service is referencing a network service group. 90 | if n, err := s.GetNetworkServiceGroup(parts[0]); err == nil { 91 | o.Kind = strings.Replace(n.Kind, "object#", "objectRef#", 1) 92 | o.ObjectID = n.ObjectID 93 | return o, nil 94 | } 95 | } 96 | 97 | p, err := protocolFromValue(parts[0]) 98 | if err != nil { 99 | return nil, err 100 | } 101 | 102 | if len(parts) == 1 || parts[1] == "" { 103 | o.Kind = "NetworkProtocol" 104 | o.Value = p.Prefix 105 | return o, nil 106 | } 107 | 108 | o.Kind = p.Kind 109 | o.Value = fmt.Sprintf("%s/%s", p.Prefix, parts[1]) 110 | 111 | return o, nil 112 | } 113 | 114 | var regexpService = regexp.MustCompile(`^= 2 && !regexpPorts.MatchString(parts[1]) { 61 | switch parts[0] { 62 | case "icmp": 63 | if part1, ok := icmpType[parts[1]]; ok { 64 | parts[1] = part1 65 | } 66 | case "tcp": 67 | if part1, ok := tcpType[parts[1]]; ok { 68 | parts[1] = part1 69 | } else { 70 | part1, err := net.LookupPort(parts[0], parts[1]) 71 | if err == nil { 72 | parts[1] = strconv.Itoa(part1) 73 | } 74 | } 75 | case "udp": 76 | if part1, ok := udpType[parts[1]]; ok { 77 | parts[1] = part1 78 | } else { 79 | part1, err := net.LookupPort(parts[0], parts[1]) 80 | if err == nil { 81 | parts[1] = strconv.Itoa(part1) 82 | } 83 | } 84 | } 85 | } 86 | 87 | return strings.Join(parts, "/") 88 | } 89 | 90 | // ListNetworkServiceGroups returns a collection of network service groups. 91 | func (s *objectsService) ListNetworkServiceGroups() (*NetworkServiceGroupCollection, error) { 92 | result := &NetworkServiceGroupCollection{} 93 | page := 0 94 | 95 | for { 96 | offset := page * s.pageLimit 97 | u := fmt.Sprintf("/api/objects/networkservicegroups?limit=%d&offset=%d", s.pageLimit, offset) 98 | 99 | req, err := s.newRequest("GET", u, nil) 100 | if err != nil { 101 | return nil, err 102 | } 103 | 104 | n := &NetworkServiceGroupCollection{} 105 | _, err = s.do(req, n) 106 | if err != nil { 107 | return nil, err 108 | } 109 | 110 | result.RangeInfo = n.RangeInfo 111 | result.Items = append(result.Items, n.Items...) 112 | result.Kind = n.Kind 113 | result.SelfLink = n.SelfLink 114 | 115 | if n.RangeInfo.Offset+n.RangeInfo.Limit == n.RangeInfo.Total { 116 | break 117 | } 118 | page++ 119 | } 120 | 121 | return result, nil 122 | } 123 | 124 | // CreateNetworkServiceGroup creates a new network service group. 125 | func (s *objectsService) CreateNetworkServiceGroup(name, description string, members []string) (*NetworkServiceGroup, error) { 126 | u := "/api/objects/networkservicegroups" 127 | 128 | n := NetworkServiceGroup{ 129 | Name: name, 130 | Description: description, 131 | Kind: "object#NetworkServiceGroup", 132 | } 133 | 134 | for _, member := range members { 135 | o, err := s.objectFromService(member) 136 | if err != nil { 137 | return nil, err 138 | } 139 | 140 | n.Members = append(n.Members, o) 141 | } 142 | 143 | req, err := s.newRequest("POST", u, n) 144 | if err != nil { 145 | return nil, err 146 | } 147 | 148 | _, err = s.do(req, nil) 149 | if err != nil { 150 | return nil, err 151 | } 152 | 153 | return s.GetNetworkServiceGroup(name) 154 | } 155 | 156 | // GetNetworkServiceGroup retrieves a network service group. 157 | func (s *objectsService) GetNetworkServiceGroup(name string) (*NetworkServiceGroup, error) { 158 | u := fmt.Sprintf("/api/objects/networkservicegroups/%s", name) 159 | 160 | req, err := s.newRequest("GET", u, nil) 161 | if err != nil { 162 | return nil, err 163 | } 164 | 165 | n := &NetworkServiceGroup{} 166 | _, err = s.do(req, n) 167 | 168 | return n, err 169 | } 170 | 171 | // UpdateNetworkServiceGroup updates a network service group. 172 | func (s *objectsService) UpdateNetworkServiceGroup(name, description string, members []string) (*NetworkServiceGroup, error) { 173 | u := fmt.Sprintf("/api/objects/networkservicegroups/%s", name) 174 | 175 | n := NetworkServiceGroup{ 176 | Name: name, 177 | Description: description, 178 | Kind: "object#NetworkServiceGroup", 179 | } 180 | 181 | for _, member := range members { 182 | o, err := s.objectFromService(member) 183 | if err != nil { 184 | return nil, err 185 | } 186 | 187 | n.Members = append(n.Members, o) 188 | } 189 | 190 | req, err := s.newRequest("PUT", u, n) 191 | if err != nil { 192 | return nil, err 193 | } 194 | 195 | _, err = s.do(req, nil) 196 | if err != nil { 197 | return nil, err 198 | } 199 | 200 | return s.GetNetworkServiceGroup(name) 201 | } 202 | 203 | // DeleteNetworkServiceGroup deletes a network service group. 204 | func (s *objectsService) DeleteNetworkServiceGroup(name string) error { 205 | u := fmt.Sprintf("/api/objects/networkservicegroups/%s", name) 206 | 207 | req, err := s.newRequest("DELETE", u, nil) 208 | if err != nil { 209 | return err 210 | } 211 | 212 | _, err = s.do(req, nil) 213 | 214 | return err 215 | } 216 | -------------------------------------------------------------------------------- /ciscoasa/objects_networkservicegroups_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2017, Rutger te Nijenhuis & Sander van Harmelen 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | package ciscoasa 18 | 19 | import ( 20 | "fmt" 21 | "net/http" 22 | "testing" 23 | ) 24 | 25 | func TestCreateNetworkServiceGroup(t *testing.T) { 26 | mux, server, client := setup() 27 | defer teardown(server) 28 | 29 | mux.HandleFunc("/api/objects/networkservicegroups", func(w http.ResponseWriter, r *http.Request) { 30 | testMethod(t, r, "POST") 31 | testJSONBody(t, r, values{ 32 | "kind": "object#NetworkServiceGroup", 33 | "name": "28ec2bb3", 34 | "members": []interface{}{ 35 | map[string]interface{}{ 36 | "kind": "TcpUdpService", 37 | "value": "tcp/2121", 38 | }, 39 | map[string]interface{}{ 40 | "kind": "TcpUdpService", 41 | "value": "udp/123", 42 | }, 43 | map[string]interface{}{ 44 | "kind": "TcpUdpService", 45 | "value": "tcp/https", 46 | }, 47 | }, 48 | }) 49 | 50 | fmt.Fprint(w, ``) 51 | }) 52 | 53 | mux.HandleFunc("/api/objects/networkservicegroups/28ec2bb3", func(w http.ResponseWriter, r *http.Request) { 54 | testMethod(t, r, "GET") 55 | fmt.Fprint(w, `{ 56 | "kind": "object#NetworkServiceGroup", 57 | "selfLink": "https://localhost/api/objects/networkservicegroups/28ec2bb3", 58 | "name": "28ec2bb3", 59 | "members": [ 60 | { 61 | "kind": "TcpUdpService", 62 | "value": "tcp/2121" 63 | }, 64 | { 65 | "kind": "TcpUdpService", 66 | "value": "udp/123" 67 | }, 68 | { 69 | "kind": "TcpUdpService", 70 | "value": "tcp/https" 71 | }], 72 | "objectId": "28ec2bb3" 73 | }`) 74 | }) 75 | 76 | _, err := client.Objects.CreateNetworkServiceGroup("28ec2bb3", "", []string{"tcp/2121", "udp/123", "tcp/https"}) 77 | if err != nil { 78 | t.Errorf("Failed to create NetworkServiceGroup 28ec2bb3: %s", err) 79 | } 80 | } 81 | 82 | func TestGetNetworkServiceGroup(t *testing.T) { 83 | mux, server, client := setup() 84 | defer teardown(server) 85 | 86 | mux.HandleFunc("/api/objects/networkservicegroups/28ec2bb3", func(w http.ResponseWriter, r *http.Request) { 87 | testMethod(t, r, "GET") 88 | fmt.Fprint(w, `{ 89 | "kind": "object#NetworkServiceGroup", 90 | "selfLink": "https://localhost/api/objects/networkservicegroups/28ec2bb3", 91 | "name": "28ec2bb3", 92 | "members": [ 93 | { 94 | "kind": "TcpUdpService", 95 | "value": "tcp/2121" 96 | }, 97 | { 98 | "kind": "TcpUdpService", 99 | "value": "udp/123" 100 | }, 101 | { 102 | "kind": "TcpUdpService", 103 | "value": "tcp/https" 104 | }], 105 | "objectId": "28ec2bb3" 106 | }`) 107 | }) 108 | 109 | o, err := client.Objects.GetNetworkServiceGroup("28ec2bb3") 110 | if err != nil { 111 | t.Fatalf("GetNetworkServiceGroup got NetworkServiceGroup 28ec2bb3: %s", err) 112 | } 113 | 114 | if o.Members[0].Value != "tcp/2121" { 115 | t.Errorf("Failed on GetNetworkServiceGroup 28ec2bb3, expected value tcp/2121, got %s", o.Members[0].Value) 116 | } 117 | if o.Members[1].Value != "udp/123" { 118 | t.Errorf("Failed on GetNetworkServiceGroup 28ec2bb3, expected value udp/123, got %s", o.Members[1].Value) 119 | } 120 | if o.Members[2].Value != "tcp/https" { 121 | t.Errorf("Failed on GetNetworkServiceGroup 28ec2bb3, expected value tcp/https, got %s", o.Members[2].Value) 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /ciscoasa/objects_networkservices.go: -------------------------------------------------------------------------------- 1 | package ciscoasa 2 | 3 | import "fmt" 4 | 5 | // NetworkServiceCollection represents a collection of network services. 6 | type NetworkServiceCollection struct { 7 | RangeInfo RangeInfo `json:"rangeInfo"` 8 | Items []*NetworkService `json:"items"` 9 | Kind string `json:"kind"` 10 | SelfLink string `json:"selfLink"` 11 | } 12 | 13 | // NetworkService represents a network service. 14 | type NetworkService struct { 15 | Name string `json:"name"` 16 | Description string `json:"description,omitempty"` 17 | Value string `json:"value"` 18 | Kind string `json:"kind"` 19 | ObjectID string `json:"objectId,omitempty"` 20 | SelfLink string `json:"selfLink,omitempty"` 21 | } 22 | 23 | // ListNetworkServices returns a collection of network services. 24 | func (s *objectsService) ListNetworkServices() (*NetworkServiceCollection, error) { 25 | result := &NetworkServiceCollection{} 26 | page := 0 27 | 28 | for { 29 | offset := page * s.pageLimit 30 | u := fmt.Sprintf("/api/objects/networkservices?limit=%d&offset=%d", s.pageLimit, offset) 31 | 32 | req, err := s.newRequest("GET", u, nil) 33 | if err != nil { 34 | return nil, err 35 | } 36 | 37 | n := &NetworkServiceCollection{} 38 | _, err = s.do(req, n) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | result.RangeInfo = n.RangeInfo 44 | result.Items = append(result.Items, n.Items...) 45 | result.Kind = n.Kind 46 | result.SelfLink = n.SelfLink 47 | 48 | if n.RangeInfo.Offset+n.RangeInfo.Limit == n.RangeInfo.Total { 49 | break 50 | } 51 | page++ 52 | } 53 | return result, nil 54 | } 55 | 56 | // CreateNetworkService creates a new network service. 57 | func (s *objectsService) CreateNetworkService(name, description, service string) (*NetworkService, error) { 58 | u := "/api/objects/networkservices" 59 | 60 | o, err := s.kindFromService(service) 61 | if err != nil { 62 | return nil, err 63 | } 64 | 65 | n := &NetworkService{ 66 | Name: name, 67 | Description: description, 68 | Value: o.Value, 69 | Kind: o.Kind, 70 | } 71 | 72 | req, err := s.newRequest("POST", u, n) 73 | if err != nil { 74 | return nil, err 75 | } 76 | 77 | _, err = s.do(req, nil) 78 | if err != nil { 79 | return nil, err 80 | } 81 | 82 | return s.GetNetworkService(name) 83 | } 84 | 85 | // GetNetworkService retrieves a network service. 86 | func (s *objectsService) GetNetworkService(name string) (*NetworkService, error) { 87 | u := fmt.Sprintf("/api/objects/networkservices/%s", name) 88 | 89 | req, err := s.newRequest("GET", u, nil) 90 | if err != nil { 91 | return nil, err 92 | } 93 | 94 | n := &NetworkService{} 95 | _, err = s.do(req, n) 96 | 97 | return n, err 98 | } 99 | 100 | // UpdateNetworkService updates a network service. 101 | func (s *objectsService) UpdateNetworkService(name, description, service string) (*NetworkService, error) { 102 | u := fmt.Sprintf("/api/objects/networkservices/%s", name) 103 | 104 | o, err := s.kindFromService(service) 105 | if err != nil { 106 | return nil, err 107 | } 108 | 109 | n := &NetworkService{ 110 | Name: name, 111 | Description: description, 112 | Value: o.Value, 113 | Kind: o.Kind, 114 | } 115 | 116 | req, err := s.newRequest("PUT", u, n) 117 | if err != nil { 118 | return nil, err 119 | } 120 | 121 | _, err = s.do(req, nil) 122 | if err != nil { 123 | return nil, err 124 | } 125 | 126 | return s.GetNetworkService(name) 127 | } 128 | 129 | // DeleteNetworkService deletes a network server. 130 | func (s *objectsService) DeleteNetworkService(name string) error { 131 | u := fmt.Sprintf("/api/objects/networkservices/%s", name) 132 | 133 | req, err := s.newRequest("DELETE", u, nil) 134 | if err != nil { 135 | return err 136 | } 137 | 138 | _, err = s.do(req, nil) 139 | 140 | return err 141 | } 142 | -------------------------------------------------------------------------------- /ciscoasa/objects_timeranges.go: -------------------------------------------------------------------------------- 1 | package ciscoasa 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // TimeRangeCollection represents a collection of time ranges. 8 | type TimeRangeCollection struct { 9 | RangeInfo RangeInfo `json:"rangeInfo"` 10 | Items []*TimeRange `json:"items"` 11 | Kind string `json:"kind"` 12 | SelfLink string `json:"selfLink"` 13 | } 14 | 15 | type TRValue struct { 16 | Start string `json:"start"` 17 | End string `json:"end"` 18 | Periodic []*Periodic `json:"periodic"` 19 | } 20 | 21 | // TimeRange represents a time range. 22 | type TimeRange struct { 23 | Name string `json:"name,omitempty"` 24 | Value *TRValue `json:"value,omitempty"` 25 | Kind string `json:"kind"` 26 | ObjectID string `json:"objectId,omitempty"` 27 | SelfLink string `json:"selfLink,omitempty"` 28 | } 29 | 30 | // ListTimeRange returns a collection of time ranges. 31 | func (s *objectsService) ListTimeRange() (*TimeRangeCollection, error) { 32 | result := &TimeRangeCollection{} 33 | page := 0 34 | 35 | for { 36 | offset := page * s.pageLimit 37 | u := fmt.Sprintf("/api/objects/timeranges?limit=%d&offset=%d", s.pageLimit, offset) 38 | 39 | req, err := s.newRequest("GET", u, nil) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | n := &TimeRangeCollection{} 45 | _, err = s.do(req, n) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | result.RangeInfo = n.RangeInfo 51 | result.Items = append(result.Items, n.Items...) 52 | result.Kind = n.Kind 53 | result.SelfLink = n.SelfLink 54 | 55 | if n.RangeInfo.Offset+n.RangeInfo.Limit == n.RangeInfo.Total { 56 | break 57 | } 58 | page++ 59 | } 60 | return result, nil 61 | } 62 | 63 | // CreateTimeRange creates a new time range. 64 | func (s *objectsService) CreateTimeRange(name, start, end string, periodic []*Periodic) (*TimeRange, error) { 65 | u := "/api/objects/timeranges" 66 | 67 | // o, err := s.objectFromService(service) 68 | // if err != nil { 69 | // return nil, err 70 | // } 71 | value := &TRValue{ 72 | Start: start, 73 | End: end, 74 | Periodic: periodic, 75 | } 76 | 77 | n := &TimeRange{ 78 | Name: name, 79 | Value: value, 80 | Kind: "object#TimeRange", 81 | } 82 | 83 | req, err := s.newRequest("POST", u, n) 84 | if err != nil { 85 | return nil, err 86 | } 87 | 88 | _, err = s.do(req, nil) 89 | if err != nil { 90 | return nil, err 91 | } 92 | 93 | return s.GetTimeRange(name) 94 | } 95 | 96 | // GetTimeRange retrieves a time range. 97 | func (s *objectsService) GetTimeRange(name string) (*TimeRange, error) { 98 | u := fmt.Sprintf("/api/objects/timeranges/%s", name) 99 | 100 | req, err := s.newRequest("GET", u, nil) 101 | if err != nil { 102 | return nil, err 103 | } 104 | 105 | n := &TimeRange{} 106 | _, err = s.do(req, n) 107 | 108 | return n, err 109 | } 110 | 111 | // UpdateTimeRange updates a time range. 112 | func (s *objectsService) UpdateTimeRange(name, start, end string, periodic []*Periodic) (*TimeRange, error) { 113 | u := fmt.Sprintf("/api/objects/timeranges/%s", name) 114 | 115 | value := &TRValue{ 116 | Start: start, 117 | End: end, 118 | Periodic: periodic, 119 | } 120 | 121 | n := &TimeRange{ 122 | Name: name, 123 | Value: value, 124 | Kind: "object#TimeRange", 125 | } 126 | 127 | req, err := s.newRequest("PUT", u, n) 128 | if err != nil { 129 | return nil, err 130 | } 131 | 132 | _, err = s.do(req, nil) 133 | if err != nil { 134 | return nil, err 135 | } 136 | 137 | return s.GetTimeRange(name) 138 | } 139 | 140 | // DeleteTimeRange deletes a time range. 141 | func (s *objectsService) DeleteTimeRange(name string) error { 142 | u := fmt.Sprintf("/api/objects/timeranges/%s", name) 143 | 144 | req, err := s.newRequest("DELETE", u, nil) 145 | if err != nil { 146 | return err 147 | } 148 | 149 | _, err = s.do(req, nil) 150 | 151 | return err 152 | } 153 | -------------------------------------------------------------------------------- /ciscoasa/routing.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2017, Rutger te Nijenhuis & Sander van Harmelen 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | package ciscoasa 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | "net" 23 | ) 24 | 25 | type routingService struct { 26 | *Client 27 | } 28 | 29 | // RoutingObjectCollection represents a collection of routing objects. 30 | type RoutingObjectCollection struct { 31 | RangeInfo RangeInfo `json:"rangeInfo"` 32 | Items []*RoutingObject `json:"items"` 33 | Kind string `json:"kind"` 34 | SelfLink string `json:"selfLink"` 35 | } 36 | 37 | // RoutingObject represents a routing object. 38 | type RoutingObject struct { 39 | DistanceMetric int `json:"distanceMetric"` 40 | Gateway *AddressObject `json:"gateway"` 41 | Interface struct { 42 | Name string `json:"name"` 43 | Kind string `json:"kind"` 44 | ObjectID string `json:"objectId,omitempty"` 45 | } `json:"interface"` 46 | Network *AddressObject `json:"network"` 47 | Tracked bool `json:"tracked,omitempty"` 48 | Tunneled bool `json:"tunneled,omitempty"` 49 | Kind string `json:"kind"` 50 | ObjectID string `json:"objectId,omitempty"` 51 | SelfLink string `json:"selfLink,omitempty"` 52 | } 53 | 54 | // ListStaticRoutes returns a collection of static routes. 55 | func (s *routingService) ListStaticRoutes() (*RoutingObjectCollection, error) { 56 | u := "/api/routing/static" 57 | 58 | req, err := s.newRequest("GET", u, nil) 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | r := &RoutingObjectCollection{} 64 | _, err = s.do(req, r) 65 | 66 | return r, err 67 | } 68 | 69 | // CreateStaticRoute creates a static route. 70 | func (s *routingService) CreateStaticRoute(iface, network, gateway string, metric int, tracked, tunneled bool) (string, error) { 71 | u := "/api/routing/static" 72 | 73 | if metric < 1 || metric > 255 { 74 | return "", errors.New("metric must be between 0 and 255") 75 | } 76 | 77 | // Confirm that the gateway specifies an IP address before trying to 78 | // create an AddressObject from the given value. 79 | addr := net.ParseIP(gateway) 80 | if addr == nil { 81 | return "", fmt.Errorf("gateway must be an IP address") 82 | } 83 | 84 | gatewayObject, err := s.Objects.objectFromAddress(gateway) 85 | if err != nil { 86 | return "", err 87 | } 88 | 89 | networkObject, err := s.Objects.objectFromAddress(network) 90 | if err != nil { 91 | return "", err 92 | } 93 | 94 | r := &RoutingObject{ 95 | DistanceMetric: metric, 96 | Gateway: gatewayObject, 97 | Network: networkObject, 98 | Tracked: tracked, 99 | Tunneled: tunneled, 100 | Kind: fmt.Sprintf("object#%sRoute", networkObject.Kind[:4]), 101 | } 102 | 103 | r.Interface.Name = iface 104 | r.Interface.Kind = "objectRef#Interface" 105 | 106 | req, err := s.newRequest("POST", u, r) 107 | if err != nil { 108 | return "", err 109 | } 110 | 111 | resp, err := s.do(req, nil) 112 | if err != nil { 113 | return "", err 114 | } 115 | 116 | return idFromResponse(resp) 117 | } 118 | 119 | // GetNetworkObject retrieves a network object. 120 | func (s *routingService) GetStaticRoute(routeID string) (*RoutingObject, error) { 121 | u := fmt.Sprintf("/api/routing/static/%s", routeID) 122 | 123 | req, err := s.newRequest("GET", u, nil) 124 | if err != nil { 125 | return nil, err 126 | } 127 | 128 | r := &RoutingObject{} 129 | _, err = s.do(req, r) 130 | 131 | return r, err 132 | } 133 | 134 | // UpdateStaticRoute updates a static route. 135 | func (s *routingService) UpdateStaticRoute(routeID, iface, network, gateway string, metric int, tracked, tunneled bool) (string, error) { 136 | u := fmt.Sprintf("/api/routing/static/%s", routeID) 137 | 138 | if metric < 1 || metric > 255 { 139 | return "", errors.New("metric must be between 0 and 255") 140 | } 141 | 142 | // Confirm that the gateway specifies an IP address before trying to 143 | // create an AddressObject from the given value. 144 | addr := net.ParseIP(gateway) 145 | if addr == nil { 146 | return "", fmt.Errorf("gateway must be an IP address") 147 | } 148 | 149 | gatewayObject, err := s.Objects.objectFromAddress(gateway) 150 | if err != nil { 151 | return "", err 152 | } 153 | 154 | networkObject, err := s.Objects.objectFromAddress(network) 155 | if err != nil { 156 | return "", err 157 | } 158 | 159 | r := &RoutingObject{ 160 | DistanceMetric: metric, 161 | Gateway: gatewayObject, 162 | Network: networkObject, 163 | Tracked: tracked, 164 | Tunneled: tunneled, 165 | Kind: fmt.Sprintf("object#%sRoute", networkObject.Kind[:4]), 166 | } 167 | 168 | r.Interface.Name = iface 169 | r.Interface.Kind = "objectRef#Interface" 170 | 171 | req, err := s.newRequest("PUT", u, r) 172 | if err != nil { 173 | return "", err 174 | } 175 | 176 | resp, err := s.do(req, nil) 177 | if err != nil { 178 | return "", err 179 | } 180 | 181 | return idFromResponse(resp) 182 | } 183 | 184 | // DeleteStaticRoute deletes a static route. 185 | func (s *routingService) DeleteStaticRoute(routeID string) error { 186 | u := fmt.Sprintf("/api/routing/static/%s", routeID) 187 | 188 | req, err := s.newRequest("DELETE", u, nil) 189 | if err != nil { 190 | return err 191 | } 192 | 193 | _, err = s.do(req, nil) 194 | 195 | return err 196 | } 197 | -------------------------------------------------------------------------------- /ciscoasa/save.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2017, Rutger te Nijenhuis & Sander van Harmelen 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | package ciscoasa 18 | 19 | type saveService struct { 20 | *Client 21 | } 22 | 23 | func (s *saveService) WriteMem() error { 24 | req, err := s.newRequest("POST", "/api/commands/writemem", nil) 25 | if err != nil { 26 | return err 27 | } 28 | 29 | _, err = s.do(req, nil) 30 | if err != nil { 31 | return err 32 | } 33 | 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /ciscoasa/service_type.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2017, Rutger te Nijenhuis & Sander van Harmelen 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | package ciscoasa 18 | 19 | var icmpType = map[string]string{ 20 | "echo-reply": "0", 21 | "unreachable": "3", 22 | "source-quench": "4", 23 | "redirect": "5", 24 | "alternate-address": "6", 25 | "echo": "8", 26 | "router-advertisement": "9", 27 | "router-solicitation": "10", 28 | "time-exceeded": "11", 29 | "parameter-problem": "12", 30 | "timestamp-request": "13", 31 | "timestamp-reply": "14", 32 | "information-request": "15", 33 | "information-reply": "16", 34 | "mask-request": "17", 35 | "mask-reply": "18", 36 | "conversion-error": "31", 37 | "mobile-redirect": "32", 38 | } 39 | 40 | var tcpType = map[string]string{ 41 | "imap4": "143", 42 | "pim-auto-rp": "496", 43 | "rsh": "514", 44 | "lpd": "515", 45 | "kerberos": "750", 46 | "lotusnotes": "1352", 47 | "citrix-ica": "1494", 48 | "sqlnet": "1521", 49 | "h323": "1720", 50 | "ctiqbe": "2748", 51 | "pcanywhere-data": "5631", 52 | } 53 | 54 | var udpType = map[string]string{ 55 | "dnsix": "195", 56 | "mobile-ip": "434", 57 | "pim-auto-rp": "496", 58 | "rip": "520", 59 | "kerberos": "750", 60 | "radius": "1645", 61 | "radius-acct": "1646", 62 | "secureid-udp": "5510", 63 | "pcanywhere-status": "5632", 64 | } 65 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/CiscoDevNet/go-ciscoasa 2 | 3 | go 1.16 4 | --------------------------------------------------------------------------------