mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-27 23:19:58 +00:00
TUN-5675: Remove github.com/dgrijalva/jwt-go dependency by upgrading coredns version
This commit is contained in:
21
vendor/github.com/coredns/caddy/.gitattributes
generated
vendored
Normal file
21
vendor/github.com/coredns/caddy/.gitattributes
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# shell scripts should not use tabs to indent!
|
||||
*.bash text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||
*.sh text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||
|
||||
# files for systemd (shell-similar)
|
||||
*.path text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||
*.service text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||
*.timer text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||
|
||||
# go fmt will enforce this, but in case a user has not called "go fmt" allow GIT to catch this:
|
||||
*.go text eol=lf core.whitespace whitespace=indent-with-non-tab,trailing-space,tabwidth=4
|
||||
go.mod text eol=lf
|
||||
go.sum text eol=lf
|
||||
|
||||
*.txt text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||
*.tpl text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||
*.htm text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||
*.html text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||
*.md text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||
*.yml text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||
.git* text eol=auto core.whitespace whitespace=trailing-space
|
22
vendor/github.com/coredns/caddy/.gitignore
generated
vendored
Normal file
22
vendor/github.com/coredns/caddy/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
_gitignore/
|
||||
Vagrantfile
|
||||
.vagrant/
|
||||
/.idea
|
||||
|
||||
dist/builds/
|
||||
dist/release/
|
||||
|
||||
error.log
|
||||
access.log
|
||||
|
||||
/*.conf
|
||||
Caddyfile
|
||||
!caddyfile/
|
||||
|
||||
og_static/
|
||||
|
||||
.vscode/
|
||||
|
||||
*.bat
|
201
vendor/github.com/coredns/caddy/LICENSE.txt
generated
vendored
Normal file
201
vendor/github.com/coredns/caddy/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
199
vendor/github.com/coredns/caddy/README.md
generated
vendored
Normal file
199
vendor/github.com/coredns/caddy/README.md
generated
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
THIS IS A FORK OF CADDY v1 - EVERYTHING IS STRIPPED EXCEPT THE PIECES NEEDED IN COREDNS.
|
||||
|
||||
|
||||
Caddy is a **production-ready** open-source web server that is fast, easy to use, and makes you more productive.
|
||||
|
||||
Available for Windows, Mac, Linux, BSD, Solaris, and [Android](https://github.com/caddyserver/caddy/wiki/Running-Caddy-on-Android).
|
||||
|
||||
<p align="center">
|
||||
<b>Thanks to our special sponsor:</b>
|
||||
<br><br>
|
||||
<a href="https://relicabackup.com"><img src="https://caddyserver.com/resources/images/sponsors/relica.png" width="220" alt="Relica - Cross-platform file backup to the cloud, local disks, or other computers"></a>
|
||||
</p>
|
||||
|
||||
## Menu
|
||||
|
||||
- [Features](#features)
|
||||
- [Install](#install)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Running in Production](#running-in-production)
|
||||
- [Contributing](#contributing)
|
||||
- [Donors](#donors)
|
||||
- [About the Project](#about-the-project)
|
||||
|
||||
## Features
|
||||
|
||||
- **Easy configuration** with the Caddyfile
|
||||
- **Automatic HTTPS** on by default (via [Let's Encrypt](https://letsencrypt.org))
|
||||
- **HTTP/2** by default
|
||||
- **Virtual hosting** so multiple sites just work
|
||||
- Experimental **QUIC support** for cutting-edge transmissions
|
||||
- TLS session ticket **key rotation** for more secure connections
|
||||
- **Extensible with plugins** because a convenient web server is a helpful one
|
||||
- **Runs anywhere** with **no external dependencies** (not even libc)
|
||||
|
||||
[See a more complete list of features built into Caddy.](https://caddyserver.com/#features) On top of all those, Caddy does even more with plugins: choose which plugins you want at [download](https://caddyserver.com/download).
|
||||
|
||||
Altogether, Caddy can do things other web servers simply cannot do. Its features and plugins save you time and mistakes, and will cheer you up. Your Caddy instance takes care of the details for you!
|
||||
|
||||
|
||||
<p align="center">
|
||||
<b>Powered by</b>
|
||||
<br>
|
||||
<a href="https://github.com/mholt/certmagic"><img src="https://user-images.githubusercontent.com/1128849/49704830-49d37200-fbd5-11e8-8385-767e0cd033c3.png" alt="CertMagic" width="250"></a>
|
||||
</p>
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
Caddy binaries have no dependencies and are available for every platform. Get Caddy any of these ways:
|
||||
|
||||
- **[Download page](https://caddyserver.com/download)** (RECOMMENDED) allows you to customize your build in the browser
|
||||
- **[Latest release](https://github.com/caddyserver/caddy/releases/latest)** for pre-built, vanilla binaries
|
||||
- **[AWS Marketplace](https://aws.amazon.com/marketplace/pp/B07J1WNK75?qid=1539015041932&sr=0-1&ref_=srh_res_product_title&cl_spe=C)** makes it easy to deploy directly to your cloud environment. <a href="https://aws.amazon.com/marketplace/pp/B07J1WNK75?qid=1539015041932&sr=0-1&ref_=srh_res_product_title&cl_spe=C" target="_blank">
|
||||
<img src="https://s3.amazonaws.com/cloudformation-examples/cloudformation-launch-stack.png" alt="Get Caddy on the AWS Marketplace" height="25"/></a>
|
||||
|
||||
|
||||
## Build
|
||||
|
||||
To build from source you need **[Git](https://git-scm.com/downloads)** and **[Go](https://golang.org/doc/install)** (1.13 or newer).
|
||||
|
||||
**To build Caddy without plugins:**
|
||||
|
||||
- Run `go get github.com/caddyserver/caddy/caddy`
|
||||
|
||||
Caddy will be installed to your `$GOPATH/bin` folder.
|
||||
|
||||
With these instructions, the binary will not have embedded version information (see [golang/go#29228](https://github.com/golang/go/issues/29228)), but it is fine for a quick start.
|
||||
|
||||
**To build Caddy with plugins (and with version information):**
|
||||
|
||||
There is no need to modify the Caddy code to build it with plugins. We will create a simple Go module with our own `main()` that you can use to make custom Caddy builds.
|
||||
- Create a new folder anywhere and within create a Go file (with an extension of `.go`, such as `main.go`) with the contents below, adjusting to import the plugins you want to include:
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/caddyserver/caddy/caddy/caddymain"
|
||||
|
||||
// plug in plugins here, for example:
|
||||
// _ "import/path/here"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// optional: disable telemetry
|
||||
// caddymain.EnableTelemetry = false
|
||||
caddymain.Run()
|
||||
}
|
||||
```
|
||||
3. `go mod init caddy`
|
||||
4. Run `go get github.com/caddyserver/caddy`
|
||||
5. `go install` will then create your binary at `$GOPATH/bin`, or `go build` will put it in the current directory.
|
||||
|
||||
**To install Caddy's source code for development:**
|
||||
|
||||
- Run `git clone https://github.com/caddyserver/caddy.git` in any folder (doesn't have to be in GOPATH).
|
||||
|
||||
You can make changes to the source code from that clone and checkout any commit or tag you wish to develop on.
|
||||
|
||||
When building from source, telemetry is enabled by default. You can disable it by changing `caddymain.EnableTelemetry = false` in run.go, or use the `-disabled-metrics` flag at runtime to disable only certain metrics.
|
||||
|
||||
|
||||
## Quick Start
|
||||
|
||||
To serve static files from the current working directory, run:
|
||||
|
||||
```
|
||||
caddy
|
||||
```
|
||||
|
||||
Caddy's default port is 2015, so open your browser to [http://localhost:2015](http://localhost:2015).
|
||||
|
||||
### Go from 0 to HTTPS in 5 seconds
|
||||
|
||||
If the `caddy` binary has permission to bind to low ports and your domain name's DNS records point to the machine you're on:
|
||||
|
||||
```
|
||||
caddy -host example.com
|
||||
```
|
||||
|
||||
This command serves static files from the current directory over HTTPS. Certificates are automatically obtained and renewed for you! Caddy is also automatically configuring ports 80 and 443 for you, and redirecting HTTP to HTTPS. Cool, huh?
|
||||
|
||||
### Customizing your site
|
||||
|
||||
To customize how your site is served, create a file named Caddyfile by your site and paste this into it:
|
||||
|
||||
```plain
|
||||
localhost
|
||||
|
||||
push
|
||||
browse
|
||||
websocket /echo cat
|
||||
ext .html
|
||||
log /var/log/access.log
|
||||
proxy /api 127.0.0.1:7005
|
||||
header /api Access-Control-Allow-Origin *
|
||||
```
|
||||
|
||||
When you run `caddy` in that directory, it will automatically find and use that Caddyfile.
|
||||
|
||||
This simple file enables server push (via Link headers), allows directory browsing (for folders without an index file), hosts a WebSocket echo server at /echo, serves clean URLs, logs requests to an access log, proxies all API requests to a backend on port 7005, and adds the coveted `Access-Control-Allow-Origin: *` header for all responses from the API.
|
||||
|
||||
Wow! Caddy can do a lot with just a few lines.
|
||||
|
||||
### Doing more with Caddy
|
||||
|
||||
To host multiple sites and do more with the Caddyfile, please see the [Caddyfile tutorial](https://caddyserver.com/tutorial/caddyfile).
|
||||
|
||||
Sites with qualifying hostnames are served over [HTTPS by default](https://caddyserver.com/docs/automatic-https).
|
||||
|
||||
Caddy has a nice little command line interface. Run `caddy -h` to view basic help or see the [CLI documentation](https://caddyserver.com/docs/cli) for details.
|
||||
|
||||
|
||||
## Running in Production
|
||||
|
||||
Caddy is production-ready if you find it to be a good fit for your site and workflow.
|
||||
|
||||
**Running as root:** We advise against this. You can still listen on ports < 1024 on Linux using setcap like so: `sudo setcap cap_net_bind_service=+ep ./caddy`
|
||||
|
||||
The Caddy project does not officially maintain any system-specific integrations nor suggest how to administer your own system. But your download file includes [unofficial resources](https://github.com/caddyserver/caddy/tree/master/dist/init) contributed by the community that you may find helpful for running Caddy in production.
|
||||
|
||||
How you choose to run Caddy is up to you. Many users are satisfied with `nohup caddy &`. Others use `screen`. Users who need Caddy to come back up after reboots either do so in the script that caused the reboot, add a command to an init script, or configure a service with their OS.
|
||||
|
||||
If you have questions or concerns about Caddy' underlying crypto implementations, consult Go's [crypto packages](https://golang.org/pkg/crypto), starting with their documentation, then issues, then the code itself; as Caddy uses mainly those libraries.
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
**[Join our forum](https://caddy.community) where you can chat with other Caddy users and developers!** To get familiar with the code base, try [Caddy code search on Sourcegraph](https://sourcegraph.com/github.com/caddyserver/caddy/)!
|
||||
|
||||
Please see our [contributing guidelines](https://github.com/caddyserver/caddy/blob/master/.github/CONTRIBUTING.md) for instructions. If you want to write a plugin, check out the [developer wiki](https://github.com/caddyserver/caddy/wiki).
|
||||
|
||||
We use GitHub issues and pull requests only for discussing bug reports and the development of specific changes. We welcome all other topics on the [forum](https://caddy.community)!
|
||||
|
||||
If you want to contribute to the documentation, please [submit an issue](https://github.com/caddyserver/caddy/issues/new) describing the change that should be made.
|
||||
|
||||
### Good First Issue
|
||||
|
||||
If you are looking for somewhere to start and would like to help out by working on an existing issue, take a look at our [`Good First Issue`](https://github.com/caddyserver/caddy/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) tag
|
||||
|
||||
Thanks for making Caddy -- and the Web -- better!
|
||||
|
||||
|
||||
## Donors
|
||||
|
||||
- [DigitalOcean](https://m.do.co/c/6d7bdafccf96) is hosting the Caddy project.
|
||||
- [DNSimple](https://dnsimple.link/resolving-caddy) provides DNS services for Caddy's sites.
|
||||
- [DNS Spy](https://dnsspy.io) keeps an eye on Caddy's DNS properties.
|
||||
|
||||
We thank them for their services. **If you want to help keep Caddy free, please [become a sponsor](https://github.com/sponsors/mholt)!**
|
||||
|
||||
|
||||
## About the Project
|
||||
|
||||
Caddy was born out of the need for a "batteries-included" web server that runs anywhere and doesn't have to take its configuration with it. Caddy took inspiration from [spark](https://github.com/rif/spark), [nginx](https://github.com/nginx/nginx), lighttpd,
|
||||
[Websocketd](https://github.com/joewalnes/websocketd) and [Vagrant](https://www.vagrantup.com/), which provides a pleasant mixture of features from each of them.
|
||||
|
||||
**The name "Caddy" is trademarked:** The name of the software is "Caddy", not "Caddy Server" or "CaddyServer". Please call it "Caddy" or, if you wish to clarify, "the Caddy web server". See [brand guidelines](https://caddyserver.com/brand). Caddy is a registered trademark of Light Code Labs, LLC.
|
||||
|
||||
*Author on Twitter: [@mholt6](https://twitter.com/mholt6)*
|
48
vendor/github.com/coredns/caddy/assets.go
generated
vendored
Normal file
48
vendor/github.com/coredns/caddy/assets.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package caddy
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// AssetsPath returns the path to the folder
|
||||
// where the application may store data. If
|
||||
// CADDYPATH env variable is set, that value
|
||||
// is used. Otherwise, the path is the result
|
||||
// of evaluating "$HOME/.caddy".
|
||||
func AssetsPath() string {
|
||||
if caddyPath := os.Getenv("CADDYPATH"); caddyPath != "" {
|
||||
return caddyPath
|
||||
}
|
||||
return filepath.Join(userHomeDir(), ".caddy")
|
||||
}
|
||||
|
||||
// userHomeDir returns the user's home directory according to
|
||||
// environment variables.
|
||||
//
|
||||
// Credit: http://stackoverflow.com/a/7922977/1048862
|
||||
func userHomeDir() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
|
||||
if home == "" {
|
||||
home = os.Getenv("USERPROFILE")
|
||||
}
|
||||
return home
|
||||
}
|
||||
return os.Getenv("HOME")
|
||||
}
|
1032
vendor/github.com/coredns/caddy/caddy.go
generated
vendored
Normal file
1032
vendor/github.com/coredns/caddy/caddy.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
260
vendor/github.com/coredns/caddy/caddyfile/dispenser.go
generated
vendored
Normal file
260
vendor/github.com/coredns/caddy/caddyfile/dispenser.go
generated
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package caddyfile
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Dispenser is a type that dispenses tokens, similarly to a lexer,
|
||||
// except that it can do so with some notion of structure and has
|
||||
// some really convenient methods.
|
||||
type Dispenser struct {
|
||||
filename string
|
||||
tokens []Token
|
||||
cursor int
|
||||
nesting int
|
||||
}
|
||||
|
||||
// NewDispenser returns a Dispenser, ready to use for parsing the given input.
|
||||
func NewDispenser(filename string, input io.Reader) Dispenser {
|
||||
tokens, _ := allTokens(input) // ignoring error because nothing to do with it
|
||||
return Dispenser{
|
||||
filename: filename,
|
||||
tokens: tokens,
|
||||
cursor: -1,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDispenserTokens returns a Dispenser filled with the given tokens.
|
||||
func NewDispenserTokens(filename string, tokens []Token) Dispenser {
|
||||
return Dispenser{
|
||||
filename: filename,
|
||||
tokens: tokens,
|
||||
cursor: -1,
|
||||
}
|
||||
}
|
||||
|
||||
// Next loads the next token. Returns true if a token
|
||||
// was loaded; false otherwise. If false, all tokens
|
||||
// have been consumed.
|
||||
func (d *Dispenser) Next() bool {
|
||||
if d.cursor < len(d.tokens)-1 {
|
||||
d.cursor++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NextArg loads the next token if it is on the same
|
||||
// line. Returns true if a token was loaded; false
|
||||
// otherwise. If false, all tokens on the line have
|
||||
// been consumed. It handles imported tokens correctly.
|
||||
func (d *Dispenser) NextArg() bool {
|
||||
if d.cursor < 0 {
|
||||
d.cursor++
|
||||
return true
|
||||
}
|
||||
if d.cursor >= len(d.tokens) {
|
||||
return false
|
||||
}
|
||||
if d.cursor < len(d.tokens)-1 &&
|
||||
d.tokens[d.cursor].File == d.tokens[d.cursor+1].File &&
|
||||
d.tokens[d.cursor].Line+d.numLineBreaks(d.cursor) == d.tokens[d.cursor+1].Line {
|
||||
d.cursor++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NextLine loads the next token only if it is not on the same
|
||||
// line as the current token, and returns true if a token was
|
||||
// loaded; false otherwise. If false, there is not another token
|
||||
// or it is on the same line. It handles imported tokens correctly.
|
||||
func (d *Dispenser) NextLine() bool {
|
||||
if d.cursor < 0 {
|
||||
d.cursor++
|
||||
return true
|
||||
}
|
||||
if d.cursor >= len(d.tokens) {
|
||||
return false
|
||||
}
|
||||
if d.cursor < len(d.tokens)-1 &&
|
||||
(d.tokens[d.cursor].File != d.tokens[d.cursor+1].File ||
|
||||
d.tokens[d.cursor].Line+d.numLineBreaks(d.cursor) < d.tokens[d.cursor+1].Line) {
|
||||
d.cursor++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NextBlock can be used as the condition of a for loop
|
||||
// to load the next token as long as it opens a block or
|
||||
// is already in a block. It returns true if a token was
|
||||
// loaded, or false when the block's closing curly brace
|
||||
// was loaded and thus the block ended. Nested blocks are
|
||||
// not supported.
|
||||
func (d *Dispenser) NextBlock() bool {
|
||||
if d.nesting > 0 {
|
||||
d.Next()
|
||||
if d.Val() == "}" {
|
||||
d.nesting--
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
if !d.NextArg() { // block must open on same line
|
||||
return false
|
||||
}
|
||||
if d.Val() != "{" {
|
||||
d.cursor-- // roll back if not opening brace
|
||||
return false
|
||||
}
|
||||
d.Next()
|
||||
if d.Val() == "}" {
|
||||
// Open and then closed right away
|
||||
return false
|
||||
}
|
||||
d.nesting++
|
||||
return true
|
||||
}
|
||||
|
||||
// Val gets the text of the current token. If there is no token
|
||||
// loaded, it returns empty string.
|
||||
func (d *Dispenser) Val() string {
|
||||
if d.cursor < 0 || d.cursor >= len(d.tokens) {
|
||||
return ""
|
||||
}
|
||||
return d.tokens[d.cursor].Text
|
||||
}
|
||||
|
||||
// Line gets the line number of the current token. If there is no token
|
||||
// loaded, it returns 0.
|
||||
func (d *Dispenser) Line() int {
|
||||
if d.cursor < 0 || d.cursor >= len(d.tokens) {
|
||||
return 0
|
||||
}
|
||||
return d.tokens[d.cursor].Line
|
||||
}
|
||||
|
||||
// File gets the filename of the current token. If there is no token loaded,
|
||||
// it returns the filename originally given when parsing started.
|
||||
func (d *Dispenser) File() string {
|
||||
if d.cursor < 0 || d.cursor >= len(d.tokens) {
|
||||
return d.filename
|
||||
}
|
||||
if tokenFilename := d.tokens[d.cursor].File; tokenFilename != "" {
|
||||
return tokenFilename
|
||||
}
|
||||
return d.filename
|
||||
}
|
||||
|
||||
// Args is a convenience function that loads the next arguments
|
||||
// (tokens on the same line) into an arbitrary number of strings
|
||||
// pointed to in targets. If there are fewer tokens available
|
||||
// than string pointers, the remaining strings will not be changed
|
||||
// and false will be returned. If there were enough tokens available
|
||||
// to fill the arguments, then true will be returned.
|
||||
func (d *Dispenser) Args(targets ...*string) bool {
|
||||
enough := true
|
||||
for i := 0; i < len(targets); i++ {
|
||||
if !d.NextArg() {
|
||||
enough = false
|
||||
break
|
||||
}
|
||||
*targets[i] = d.Val()
|
||||
}
|
||||
return enough
|
||||
}
|
||||
|
||||
// RemainingArgs loads any more arguments (tokens on the same line)
|
||||
// into a slice and returns them. Open curly brace tokens also indicate
|
||||
// the end of arguments, and the curly brace is not included in
|
||||
// the return value nor is it loaded.
|
||||
func (d *Dispenser) RemainingArgs() []string {
|
||||
var args []string
|
||||
|
||||
for d.NextArg() {
|
||||
if d.Val() == "{" {
|
||||
d.cursor--
|
||||
break
|
||||
}
|
||||
args = append(args, d.Val())
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
// ArgErr returns an argument error, meaning that another
|
||||
// argument was expected but not found. In other words,
|
||||
// a line break or open curly brace was encountered instead of
|
||||
// an argument.
|
||||
func (d *Dispenser) ArgErr() error {
|
||||
if d.Val() == "{" {
|
||||
return d.Err("Unexpected token '{', expecting argument")
|
||||
}
|
||||
return d.Errf("Wrong argument count or unexpected line ending after '%s'", d.Val())
|
||||
}
|
||||
|
||||
// SyntaxErr creates a generic syntax error which explains what was
|
||||
// found and what was expected.
|
||||
func (d *Dispenser) SyntaxErr(expected string) error {
|
||||
msg := fmt.Sprintf("%s:%d - Syntax error: Unexpected token '%s', expecting '%s'", d.File(), d.Line(), d.Val(), expected)
|
||||
return errors.New(msg)
|
||||
}
|
||||
|
||||
// EOFErr returns an error indicating that the dispenser reached
|
||||
// the end of the input when searching for the next token.
|
||||
func (d *Dispenser) EOFErr() error {
|
||||
return d.Errf("Unexpected EOF")
|
||||
}
|
||||
|
||||
// Err generates a custom parse-time error with a message of msg.
|
||||
func (d *Dispenser) Err(msg string) error {
|
||||
msg = fmt.Sprintf("%s:%d - Error during parsing: %s", d.File(), d.Line(), msg)
|
||||
return errors.New(msg)
|
||||
}
|
||||
|
||||
// Errf is like Err, but for formatted error messages
|
||||
func (d *Dispenser) Errf(format string, args ...interface{}) error {
|
||||
return d.Err(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// numLineBreaks counts how many line breaks are in the token
|
||||
// value given by the token index tknIdx. It returns 0 if the
|
||||
// token does not exist or there are no line breaks.
|
||||
func (d *Dispenser) numLineBreaks(tknIdx int) int {
|
||||
if tknIdx < 0 || tknIdx >= len(d.tokens) {
|
||||
return 0
|
||||
}
|
||||
return strings.Count(d.tokens[tknIdx].Text, "\n")
|
||||
}
|
||||
|
||||
// isNewLine determines whether the current token is on a different
|
||||
// line (higher line number) than the previous token. It handles imported
|
||||
// tokens correctly. If there isn't a previous token, it returns true.
|
||||
func (d *Dispenser) isNewLine() bool {
|
||||
if d.cursor < 1 {
|
||||
return true
|
||||
}
|
||||
if d.cursor > len(d.tokens)-1 {
|
||||
return false
|
||||
}
|
||||
return d.tokens[d.cursor-1].File != d.tokens[d.cursor].File ||
|
||||
d.tokens[d.cursor-1].Line+d.numLineBreaks(d.cursor-1) < d.tokens[d.cursor].Line
|
||||
}
|
198
vendor/github.com/coredns/caddy/caddyfile/json.go
generated
vendored
Normal file
198
vendor/github.com/coredns/caddy/caddyfile/json.go
generated
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package caddyfile
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const filename = "Caddyfile"
|
||||
|
||||
// ToJSON converts caddyfile to its JSON representation.
|
||||
func ToJSON(caddyfile []byte) ([]byte, error) {
|
||||
var j EncodedCaddyfile
|
||||
|
||||
serverBlocks, err := Parse(filename, bytes.NewReader(caddyfile), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, sb := range serverBlocks {
|
||||
block := EncodedServerBlock{
|
||||
Keys: sb.Keys,
|
||||
Body: [][]interface{}{},
|
||||
}
|
||||
|
||||
// Extract directives deterministically by sorting them
|
||||
var directives = make([]string, len(sb.Tokens))
|
||||
for dir := range sb.Tokens {
|
||||
directives = append(directives, dir)
|
||||
}
|
||||
sort.Strings(directives)
|
||||
|
||||
// Convert each directive's tokens into our JSON structure
|
||||
for _, dir := range directives {
|
||||
disp := NewDispenserTokens(filename, sb.Tokens[dir])
|
||||
for disp.Next() {
|
||||
block.Body = append(block.Body, constructLine(&disp))
|
||||
}
|
||||
}
|
||||
|
||||
// tack this block onto the end of the list
|
||||
j = append(j, block)
|
||||
}
|
||||
|
||||
result, err := json.Marshal(j)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// constructLine transforms tokens into a JSON-encodable structure;
|
||||
// but only one line at a time, to be used at the top-level of
|
||||
// a server block only (where the first token on each line is a
|
||||
// directive) - not to be used at any other nesting level.
|
||||
func constructLine(d *Dispenser) []interface{} {
|
||||
var args []interface{}
|
||||
|
||||
args = append(args, d.Val())
|
||||
|
||||
for d.NextArg() {
|
||||
if d.Val() == "{" {
|
||||
args = append(args, constructBlock(d))
|
||||
continue
|
||||
}
|
||||
args = append(args, d.Val())
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
// constructBlock recursively processes tokens into a
|
||||
// JSON-encodable structure. To be used in a directive's
|
||||
// block. Goes to end of block.
|
||||
func constructBlock(d *Dispenser) [][]interface{} {
|
||||
block := [][]interface{}{}
|
||||
|
||||
for d.Next() {
|
||||
if d.Val() == "}" {
|
||||
break
|
||||
}
|
||||
block = append(block, constructLine(d))
|
||||
}
|
||||
|
||||
return block
|
||||
}
|
||||
|
||||
// FromJSON converts JSON-encoded jsonBytes to Caddyfile text
|
||||
func FromJSON(jsonBytes []byte) ([]byte, error) {
|
||||
var j EncodedCaddyfile
|
||||
var result string
|
||||
|
||||
err := json.Unmarshal(jsonBytes, &j)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for sbPos, sb := range j {
|
||||
if sbPos > 0 {
|
||||
result += "\n\n"
|
||||
}
|
||||
for i, key := range sb.Keys {
|
||||
if i > 0 {
|
||||
result += ", "
|
||||
}
|
||||
//result += standardizeScheme(key)
|
||||
result += key
|
||||
}
|
||||
result += jsonToText(sb.Body, 1)
|
||||
}
|
||||
|
||||
return []byte(result), nil
|
||||
}
|
||||
|
||||
// jsonToText recursively transforms a scope of JSON into plain
|
||||
// Caddyfile text.
|
||||
func jsonToText(scope interface{}, depth int) string {
|
||||
var result string
|
||||
|
||||
switch val := scope.(type) {
|
||||
case string:
|
||||
if strings.ContainsAny(val, "\" \n\t\r") {
|
||||
result += `"` + strings.Replace(val, "\"", "\\\"", -1) + `"`
|
||||
} else {
|
||||
result += val
|
||||
}
|
||||
case int:
|
||||
result += strconv.Itoa(val)
|
||||
case float64:
|
||||
result += fmt.Sprintf("%v", val)
|
||||
case bool:
|
||||
result += fmt.Sprintf("%t", val)
|
||||
case [][]interface{}:
|
||||
result += " {\n"
|
||||
for _, arg := range val {
|
||||
result += strings.Repeat("\t", depth) + jsonToText(arg, depth+1) + "\n"
|
||||
}
|
||||
result += strings.Repeat("\t", depth-1) + "}"
|
||||
case []interface{}:
|
||||
for i, v := range val {
|
||||
if block, ok := v.([]interface{}); ok {
|
||||
result += "{\n"
|
||||
for _, arg := range block {
|
||||
result += strings.Repeat("\t", depth) + jsonToText(arg, depth+1) + "\n"
|
||||
}
|
||||
result += strings.Repeat("\t", depth-1) + "}"
|
||||
continue
|
||||
}
|
||||
result += jsonToText(v, depth)
|
||||
if i < len(val)-1 {
|
||||
result += " "
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// TODO: Will this function come in handy somewhere else?
|
||||
/*
|
||||
// standardizeScheme turns an address like host:https into https://host,
|
||||
// or "host:" into "host".
|
||||
func standardizeScheme(addr string) string {
|
||||
if hostname, port, err := net.SplitHostPort(addr); err == nil {
|
||||
if port == "http" || port == "https" {
|
||||
addr = port + "://" + hostname
|
||||
}
|
||||
}
|
||||
return strings.TrimSuffix(addr, ":")
|
||||
}
|
||||
*/
|
||||
|
||||
// EncodedCaddyfile encapsulates a slice of EncodedServerBlocks.
|
||||
type EncodedCaddyfile []EncodedServerBlock
|
||||
|
||||
// EncodedServerBlock represents a server block ripe for encoding.
|
||||
type EncodedServerBlock struct {
|
||||
Keys []string `json:"keys"`
|
||||
Body [][]interface{} `json:"body"`
|
||||
}
|
153
vendor/github.com/coredns/caddy/caddyfile/lexer.go
generated
vendored
Normal file
153
vendor/github.com/coredns/caddy/caddyfile/lexer.go
generated
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package caddyfile
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type (
|
||||
// lexer is a utility which can get values, token by
|
||||
// token, from a Reader. A token is a word, and tokens
|
||||
// are separated by whitespace. A word can be enclosed
|
||||
// in quotes if it contains whitespace.
|
||||
lexer struct {
|
||||
reader *bufio.Reader
|
||||
token Token
|
||||
line int
|
||||
}
|
||||
|
||||
// Token represents a single parsable unit.
|
||||
Token struct {
|
||||
File string
|
||||
Line int
|
||||
Text string
|
||||
}
|
||||
)
|
||||
|
||||
// load prepares the lexer to scan an input for tokens.
|
||||
// It discards any leading byte order mark.
|
||||
func (l *lexer) load(input io.Reader) error {
|
||||
l.reader = bufio.NewReader(input)
|
||||
l.line = 1
|
||||
|
||||
// discard byte order mark, if present
|
||||
firstCh, _, err := l.reader.ReadRune()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
if firstCh != 0xFEFF {
|
||||
err := l.reader.UnreadRune()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// next loads the next token into the lexer.
|
||||
// A token is delimited by whitespace, unless
|
||||
// the token starts with a quotes character (")
|
||||
// in which case the token goes until the closing
|
||||
// quotes (the enclosing quotes are not included).
|
||||
// Inside quoted strings, quotes may be escaped
|
||||
// with a preceding \ character. No other chars
|
||||
// may be escaped. The rest of the line is skipped
|
||||
// if a "#" character is read in. Returns true if
|
||||
// a token was loaded; false otherwise.
|
||||
func (l *lexer) next() bool {
|
||||
var val []rune
|
||||
var comment, quoted, escaped bool
|
||||
|
||||
makeToken := func() bool {
|
||||
l.token.Text = string(val)
|
||||
return true
|
||||
}
|
||||
|
||||
for {
|
||||
ch, _, err := l.reader.ReadRune()
|
||||
if err != nil {
|
||||
if len(val) > 0 {
|
||||
return makeToken()
|
||||
}
|
||||
if err == io.EOF {
|
||||
return false
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if quoted {
|
||||
if !escaped {
|
||||
if ch == '\\' {
|
||||
escaped = true
|
||||
continue
|
||||
} else if ch == '"' {
|
||||
quoted = false
|
||||
return makeToken()
|
||||
}
|
||||
}
|
||||
if ch == '\n' {
|
||||
l.line++
|
||||
}
|
||||
if escaped {
|
||||
// only escape quotes
|
||||
if ch != '"' {
|
||||
val = append(val, '\\')
|
||||
}
|
||||
}
|
||||
val = append(val, ch)
|
||||
escaped = false
|
||||
continue
|
||||
}
|
||||
|
||||
if unicode.IsSpace(ch) {
|
||||
if ch == '\r' {
|
||||
continue
|
||||
}
|
||||
if ch == '\n' {
|
||||
l.line++
|
||||
comment = false
|
||||
}
|
||||
if len(val) > 0 {
|
||||
return makeToken()
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if ch == '#' {
|
||||
comment = true
|
||||
}
|
||||
|
||||
if comment {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(val) == 0 {
|
||||
l.token = Token{Line: l.line}
|
||||
if ch == '"' {
|
||||
quoted = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
val = append(val, ch)
|
||||
}
|
||||
}
|
490
vendor/github.com/coredns/caddy/caddyfile/parse.go
generated
vendored
Normal file
490
vendor/github.com/coredns/caddy/caddyfile/parse.go
generated
vendored
Normal file
@@ -0,0 +1,490 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package caddyfile
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Parse parses the input just enough to group tokens, in
|
||||
// order, by server block. No further parsing is performed.
|
||||
// Server blocks are returned in the order in which they appear.
|
||||
// Directives that do not appear in validDirectives will cause
|
||||
// an error. If you do not want to check for valid directives,
|
||||
// pass in nil instead.
|
||||
func Parse(filename string, input io.Reader, validDirectives []string) ([]ServerBlock, error) {
|
||||
p := parser{Dispenser: NewDispenser(filename, input), validDirectives: validDirectives}
|
||||
return p.parseAll()
|
||||
}
|
||||
|
||||
// allTokens lexes the entire input, but does not parse it.
|
||||
// It returns all the tokens from the input, unstructured
|
||||
// and in order.
|
||||
func allTokens(input io.Reader) ([]Token, error) {
|
||||
l := new(lexer)
|
||||
err := l.load(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var tokens []Token
|
||||
for l.next() {
|
||||
tokens = append(tokens, l.token)
|
||||
}
|
||||
return tokens, nil
|
||||
}
|
||||
|
||||
type parser struct {
|
||||
Dispenser
|
||||
block ServerBlock // current server block being parsed
|
||||
validDirectives []string // a directive must be valid or it's an error
|
||||
eof bool // if we encounter a valid EOF in a hard place
|
||||
definedSnippets map[string][]Token
|
||||
}
|
||||
|
||||
func (p *parser) parseAll() ([]ServerBlock, error) {
|
||||
var blocks []ServerBlock
|
||||
|
||||
for p.Next() {
|
||||
err := p.parseOne()
|
||||
if err != nil {
|
||||
return blocks, err
|
||||
}
|
||||
if len(p.block.Keys) > 0 {
|
||||
blocks = append(blocks, p.block)
|
||||
}
|
||||
}
|
||||
|
||||
return blocks, nil
|
||||
}
|
||||
|
||||
func (p *parser) parseOne() error {
|
||||
p.block = ServerBlock{Tokens: make(map[string][]Token)}
|
||||
|
||||
return p.begin()
|
||||
}
|
||||
|
||||
func (p *parser) begin() error {
|
||||
if len(p.tokens) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := p.addresses()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.eof {
|
||||
// this happens if the Caddyfile consists of only
|
||||
// a line of addresses and nothing else
|
||||
return nil
|
||||
}
|
||||
|
||||
if ok, name := p.isSnippet(); ok {
|
||||
if p.definedSnippets == nil {
|
||||
p.definedSnippets = map[string][]Token{}
|
||||
}
|
||||
if _, found := p.definedSnippets[name]; found {
|
||||
return p.Errf("redeclaration of previously declared snippet %s", name)
|
||||
}
|
||||
// consume all tokens til matched close brace
|
||||
tokens, err := p.snippetTokens()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.definedSnippets[name] = tokens
|
||||
// empty block keys so we don't save this block as a real server.
|
||||
p.block.Keys = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return p.blockContents()
|
||||
}
|
||||
|
||||
func (p *parser) addresses() error {
|
||||
var expectingAnother bool
|
||||
|
||||
for {
|
||||
tkn := replaceEnvVars(p.Val())
|
||||
|
||||
// special case: import directive replaces tokens during parse-time
|
||||
if tkn == "import" && p.isNewLine() {
|
||||
err := p.doImport()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Open brace definitely indicates end of addresses
|
||||
if tkn == "{" {
|
||||
if expectingAnother {
|
||||
return p.Errf("Expected another address but had '%s' - check for extra comma", tkn)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if tkn != "" { // empty token possible if user typed ""
|
||||
// Trailing comma indicates another address will follow, which
|
||||
// may possibly be on the next line
|
||||
if tkn[len(tkn)-1] == ',' {
|
||||
tkn = tkn[:len(tkn)-1]
|
||||
expectingAnother = true
|
||||
} else {
|
||||
expectingAnother = false // but we may still see another one on this line
|
||||
}
|
||||
|
||||
p.block.Keys = append(p.block.Keys, tkn)
|
||||
}
|
||||
|
||||
// Advance token and possibly break out of loop or return error
|
||||
hasNext := p.Next()
|
||||
if expectingAnother && !hasNext {
|
||||
return p.EOFErr()
|
||||
}
|
||||
if !hasNext {
|
||||
p.eof = true
|
||||
break // EOF
|
||||
}
|
||||
if !expectingAnother && p.isNewLine() {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *parser) blockContents() error {
|
||||
errOpenCurlyBrace := p.openCurlyBrace()
|
||||
if errOpenCurlyBrace != nil {
|
||||
// single-server configs don't need curly braces
|
||||
p.cursor--
|
||||
}
|
||||
|
||||
err := p.directives()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Only look for close curly brace if there was an opening
|
||||
if errOpenCurlyBrace == nil {
|
||||
err = p.closeCurlyBrace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// directives parses through all the lines for directives
|
||||
// and it expects the next token to be the first
|
||||
// directive. It goes until EOF or closing curly brace
|
||||
// which ends the server block.
|
||||
func (p *parser) directives() error {
|
||||
for p.Next() {
|
||||
// end of server block
|
||||
if p.Val() == "}" {
|
||||
break
|
||||
}
|
||||
|
||||
// special case: import directive replaces tokens during parse-time
|
||||
if p.Val() == "import" {
|
||||
err := p.doImport()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.cursor-- // cursor is advanced when we continue, so roll back one more
|
||||
continue
|
||||
}
|
||||
|
||||
// normal case: parse a directive on this line
|
||||
if err := p.directive(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// doImport swaps out the import directive and its argument
|
||||
// (a total of 2 tokens) with the tokens in the specified file
|
||||
// or globbing pattern. When the function returns, the cursor
|
||||
// is on the token before where the import directive was. In
|
||||
// other words, call Next() to access the first token that was
|
||||
// imported.
|
||||
func (p *parser) doImport() error {
|
||||
// syntax checks
|
||||
if !p.NextArg() {
|
||||
return p.ArgErr()
|
||||
}
|
||||
importPattern := replaceEnvVars(p.Val())
|
||||
if importPattern == "" {
|
||||
return p.Err("Import requires a non-empty filepath")
|
||||
}
|
||||
if p.NextArg() {
|
||||
return p.Err("Import takes only one argument (glob pattern or file)")
|
||||
}
|
||||
// splice out the import directive and its argument (2 tokens total)
|
||||
tokensBefore := p.tokens[:p.cursor-1]
|
||||
tokensAfter := p.tokens[p.cursor+1:]
|
||||
var importedTokens []Token
|
||||
|
||||
// first check snippets. That is a simple, non-recursive replacement
|
||||
if p.definedSnippets != nil && p.definedSnippets[importPattern] != nil {
|
||||
importedTokens = p.definedSnippets[importPattern]
|
||||
} else {
|
||||
// make path relative to the file of the _token_ being processed rather
|
||||
// than current working directory (issue #867) and then use glob to get
|
||||
// list of matching filenames
|
||||
absFile, err := filepath.Abs(p.Dispenser.File())
|
||||
if err != nil {
|
||||
return p.Errf("Failed to get absolute path of file: %s: %v", p.Dispenser.filename, err)
|
||||
}
|
||||
|
||||
var matches []string
|
||||
var globPattern string
|
||||
if !filepath.IsAbs(importPattern) {
|
||||
globPattern = filepath.Join(filepath.Dir(absFile), importPattern)
|
||||
} else {
|
||||
globPattern = importPattern
|
||||
}
|
||||
if strings.Count(globPattern, "*") > 1 || strings.Count(globPattern, "?") > 1 ||
|
||||
(strings.Contains(globPattern, "[") && strings.Contains(globPattern, "]")) {
|
||||
// See issue #2096 - a pattern with many glob expansions can hang for too long
|
||||
return p.Errf("Glob pattern may only contain one wildcard (*), but has others: %s", globPattern)
|
||||
}
|
||||
matches, err = filepath.Glob(globPattern)
|
||||
|
||||
if err != nil {
|
||||
return p.Errf("Failed to use import pattern %s: %v", importPattern, err)
|
||||
}
|
||||
if len(matches) == 0 {
|
||||
if strings.ContainsAny(globPattern, "*?[]") {
|
||||
log.Printf("[WARNING] No files matching import glob pattern: %s", importPattern)
|
||||
} else {
|
||||
return p.Errf("File to import not found: %s", importPattern)
|
||||
}
|
||||
}
|
||||
|
||||
// collect all the imported tokens
|
||||
|
||||
for _, importFile := range matches {
|
||||
newTokens, err := p.doSingleImport(importFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
importedTokens = append(importedTokens, newTokens...)
|
||||
}
|
||||
}
|
||||
|
||||
// splice the imported tokens in the place of the import statement
|
||||
// and rewind cursor so Next() will land on first imported token
|
||||
p.tokens = append(tokensBefore, append(importedTokens, tokensAfter...)...)
|
||||
p.cursor--
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// doSingleImport lexes the individual file at importFile and returns
|
||||
// its tokens or an error, if any.
|
||||
func (p *parser) doSingleImport(importFile string) ([]Token, error) {
|
||||
file, err := os.Open(importFile)
|
||||
if err != nil {
|
||||
return nil, p.Errf("Could not import %s: %v", importFile, err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if info, err := file.Stat(); err != nil {
|
||||
return nil, p.Errf("Could not import %s: %v", importFile, err)
|
||||
} else if info.IsDir() {
|
||||
return nil, p.Errf("Could not import %s: is a directory", importFile)
|
||||
}
|
||||
|
||||
importedTokens, err := allTokens(file)
|
||||
if err != nil {
|
||||
return nil, p.Errf("Could not read tokens while importing %s: %v", importFile, err)
|
||||
}
|
||||
|
||||
// Tack the file path onto these tokens so errors show the imported file's name
|
||||
// (we use full, absolute path to avoid bugs: issue #1892)
|
||||
filename, err := filepath.Abs(importFile)
|
||||
if err != nil {
|
||||
return nil, p.Errf("Failed to get absolute path of file: %s: %v", p.Dispenser.filename, err)
|
||||
}
|
||||
for i := 0; i < len(importedTokens); i++ {
|
||||
importedTokens[i].File = filename
|
||||
}
|
||||
|
||||
return importedTokens, nil
|
||||
}
|
||||
|
||||
// directive collects tokens until the directive's scope
|
||||
// closes (either end of line or end of curly brace block).
|
||||
// It expects the currently-loaded token to be a directive
|
||||
// (or } that ends a server block). The collected tokens
|
||||
// are loaded into the current server block for later use
|
||||
// by directive setup functions.
|
||||
func (p *parser) directive() error {
|
||||
dir := replaceEnvVars(p.Val())
|
||||
nesting := 0
|
||||
|
||||
// TODO: More helpful error message ("did you mean..." or "maybe you need to install its server type")
|
||||
if !p.validDirective(dir) {
|
||||
return p.Errf("Unknown directive '%s'", dir)
|
||||
}
|
||||
|
||||
// The directive itself is appended as a relevant token
|
||||
p.block.Tokens[dir] = append(p.block.Tokens[dir], p.tokens[p.cursor])
|
||||
|
||||
for p.Next() {
|
||||
if p.Val() == "{" {
|
||||
nesting++
|
||||
} else if p.isNewLine() && nesting == 0 {
|
||||
p.cursor-- // read too far
|
||||
break
|
||||
} else if p.Val() == "}" && nesting > 0 {
|
||||
nesting--
|
||||
} else if p.Val() == "}" && nesting == 0 {
|
||||
return p.Err("Unexpected '}' because no matching opening brace")
|
||||
} else if p.Val() == "import" && p.isNewLine() {
|
||||
if err := p.doImport(); err != nil {
|
||||
return err
|
||||
}
|
||||
p.cursor-- // cursor is advanced when we continue, so roll back one more
|
||||
continue
|
||||
}
|
||||
p.tokens[p.cursor].Text = replaceEnvVars(p.tokens[p.cursor].Text)
|
||||
p.block.Tokens[dir] = append(p.block.Tokens[dir], p.tokens[p.cursor])
|
||||
}
|
||||
|
||||
if nesting > 0 {
|
||||
return p.EOFErr()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// openCurlyBrace expects the current token to be an
|
||||
// opening curly brace. This acts like an assertion
|
||||
// because it returns an error if the token is not
|
||||
// a opening curly brace. It does NOT advance the token.
|
||||
func (p *parser) openCurlyBrace() error {
|
||||
if p.Val() != "{" {
|
||||
return p.SyntaxErr("{")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// closeCurlyBrace expects the current token to be
|
||||
// a closing curly brace. This acts like an assertion
|
||||
// because it returns an error if the token is not
|
||||
// a closing curly brace. It does NOT advance the token.
|
||||
func (p *parser) closeCurlyBrace() error {
|
||||
if p.Val() != "}" {
|
||||
return p.SyntaxErr("}")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validDirective returns true if dir is in p.validDirectives.
|
||||
func (p *parser) validDirective(dir string) bool {
|
||||
if p.validDirectives == nil {
|
||||
return true
|
||||
}
|
||||
for _, d := range p.validDirectives {
|
||||
if d == dir {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// replaceEnvVars replaces environment variables that appear in the token
|
||||
// and understands both the $UNIX and %WINDOWS% syntaxes.
|
||||
func replaceEnvVars(s string) string {
|
||||
s = replaceEnvReferences(s, "{%", "%}")
|
||||
s = replaceEnvReferences(s, "{$", "}")
|
||||
return s
|
||||
}
|
||||
|
||||
// replaceEnvReferences performs the actual replacement of env variables
|
||||
// in s, given the placeholder start and placeholder end strings.
|
||||
func replaceEnvReferences(s, refStart, refEnd string) string {
|
||||
index := strings.Index(s, refStart)
|
||||
for index != -1 {
|
||||
endIndex := strings.Index(s[index:], refEnd)
|
||||
if endIndex == -1 {
|
||||
break
|
||||
}
|
||||
|
||||
endIndex += index
|
||||
if endIndex > index+len(refStart) {
|
||||
ref := s[index : endIndex+len(refEnd)]
|
||||
s = strings.Replace(s, ref, os.Getenv(ref[len(refStart):len(ref)-len(refEnd)]), -1)
|
||||
} else {
|
||||
return s
|
||||
}
|
||||
index = strings.Index(s, refStart)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ServerBlock associates any number of keys (usually addresses
|
||||
// of some sort) with tokens (grouped by directive name).
|
||||
type ServerBlock struct {
|
||||
Keys []string
|
||||
Tokens map[string][]Token
|
||||
}
|
||||
|
||||
func (p *parser) isSnippet() (bool, string) {
|
||||
keys := p.block.Keys
|
||||
// A snippet block is a single key with parens. Nothing else qualifies.
|
||||
if len(keys) == 1 && strings.HasPrefix(keys[0], "(") && strings.HasSuffix(keys[0], ")") {
|
||||
return true, strings.TrimSuffix(keys[0][1:], ")")
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// read and store everything in a block for later replay.
|
||||
func (p *parser) snippetTokens() ([]Token, error) {
|
||||
// TODO: disallow imports in snippets for simplicity at import time
|
||||
// snippet must have curlies.
|
||||
err := p.openCurlyBrace()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
count := 1
|
||||
tokens := []Token{}
|
||||
for p.Next() {
|
||||
if p.Val() == "}" {
|
||||
count--
|
||||
if count == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if p.Val() == "{" {
|
||||
count++
|
||||
}
|
||||
tokens = append(tokens, p.tokens[p.cursor])
|
||||
}
|
||||
// make sure we're matched up
|
||||
if count != 0 {
|
||||
return nil, p.SyntaxErr("}")
|
||||
}
|
||||
return tokens, nil
|
||||
}
|
133
vendor/github.com/coredns/caddy/commands.go
generated
vendored
Normal file
133
vendor/github.com/coredns/caddy/commands.go
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package caddy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"unicode"
|
||||
|
||||
"github.com/flynn/go-shlex"
|
||||
)
|
||||
|
||||
var runtimeGoos = runtime.GOOS
|
||||
|
||||
// SplitCommandAndArgs takes a command string and parses it shell-style into the
|
||||
// command and its separate arguments.
|
||||
func SplitCommandAndArgs(command string) (cmd string, args []string, err error) {
|
||||
var parts []string
|
||||
|
||||
if runtimeGoos == "windows" {
|
||||
parts = parseWindowsCommand(command) // parse it Windows-style
|
||||
} else {
|
||||
parts, err = parseUnixCommand(command) // parse it Unix-style
|
||||
if err != nil {
|
||||
err = errors.New("error parsing command: " + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(parts) == 0 {
|
||||
err = errors.New("no command contained in '" + command + "'")
|
||||
return
|
||||
}
|
||||
|
||||
cmd = parts[0]
|
||||
if len(parts) > 1 {
|
||||
args = parts[1:]
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// parseUnixCommand parses a unix style command line and returns the
|
||||
// command and its arguments or an error
|
||||
func parseUnixCommand(cmd string) ([]string, error) {
|
||||
return shlex.Split(cmd)
|
||||
}
|
||||
|
||||
// parseWindowsCommand parses windows command lines and
|
||||
// returns the command and the arguments as an array. It
|
||||
// should be able to parse commonly used command lines.
|
||||
// Only basic syntax is supported:
|
||||
// - spaces in double quotes are not token delimiters
|
||||
// - double quotes are escaped by either backspace or another double quote
|
||||
// - except for the above case backspaces are path separators (not special)
|
||||
//
|
||||
// Many sources point out that escaping quotes using backslash can be unsafe.
|
||||
// Use two double quotes when possible. (Source: http://stackoverflow.com/a/31413730/2616179 )
|
||||
//
|
||||
// This function has to be used on Windows instead
|
||||
// of the shlex package because this function treats backslash
|
||||
// characters properly.
|
||||
func parseWindowsCommand(cmd string) []string {
|
||||
const backslash = '\\'
|
||||
const quote = '"'
|
||||
|
||||
var parts []string
|
||||
var part string
|
||||
var inQuotes bool
|
||||
var lastRune rune
|
||||
|
||||
for i, ch := range cmd {
|
||||
|
||||
if i != 0 {
|
||||
lastRune = rune(cmd[i-1])
|
||||
}
|
||||
|
||||
if ch == backslash {
|
||||
// put it in the part - for now we don't know if it's an
|
||||
// escaping char or path separator
|
||||
part += string(ch)
|
||||
continue
|
||||
}
|
||||
|
||||
if ch == quote {
|
||||
if lastRune == backslash {
|
||||
// remove the backslash from the part and add the escaped quote instead
|
||||
part = part[:len(part)-1]
|
||||
part += string(ch)
|
||||
continue
|
||||
}
|
||||
|
||||
if lastRune == quote {
|
||||
// revert the last change of the inQuotes state
|
||||
// it was an escaping quote
|
||||
inQuotes = !inQuotes
|
||||
part += string(ch)
|
||||
continue
|
||||
}
|
||||
|
||||
// normal escaping quotes
|
||||
inQuotes = !inQuotes
|
||||
continue
|
||||
|
||||
}
|
||||
|
||||
if unicode.IsSpace(ch) && !inQuotes && len(part) > 0 {
|
||||
parts = append(parts, part)
|
||||
part = ""
|
||||
continue
|
||||
}
|
||||
|
||||
part += string(ch)
|
||||
}
|
||||
|
||||
if len(part) > 0 {
|
||||
parts = append(parts, part)
|
||||
}
|
||||
|
||||
return parts
|
||||
}
|
145
vendor/github.com/coredns/caddy/controller.go
generated
vendored
Normal file
145
vendor/github.com/coredns/caddy/controller.go
generated
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package caddy
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/coredns/caddy/caddyfile"
|
||||
)
|
||||
|
||||
// Controller is given to the setup function of directives which
|
||||
// gives them access to be able to read tokens with which to
|
||||
// configure themselves. It also stores state for the setup
|
||||
// functions, can get the current context, and can be used to
|
||||
// identify a particular server block using the Key field.
|
||||
type Controller struct {
|
||||
caddyfile.Dispenser
|
||||
|
||||
// The instance in which the setup is occurring
|
||||
instance *Instance
|
||||
|
||||
// Key is the key from the top of the server block, usually
|
||||
// an address, hostname, or identifier of some sort.
|
||||
Key string
|
||||
|
||||
// OncePerServerBlock is a function that executes f
|
||||
// exactly once per server block, no matter how many
|
||||
// hosts are associated with it. If it is the first
|
||||
// time, the function f is executed immediately
|
||||
// (not deferred) and may return an error which is
|
||||
// returned by OncePerServerBlock.
|
||||
OncePerServerBlock func(f func() error) error
|
||||
|
||||
// ServerBlockIndex is the 0-based index of the
|
||||
// server block as it appeared in the input.
|
||||
ServerBlockIndex int
|
||||
|
||||
// ServerBlockKeyIndex is the 0-based index of this
|
||||
// key as it appeared in the input at the head of the
|
||||
// server block.
|
||||
ServerBlockKeyIndex int
|
||||
|
||||
// ServerBlockKeys is a list of keys that are
|
||||
// associated with this server block. All these
|
||||
// keys, consequently, share the same tokens.
|
||||
ServerBlockKeys []string
|
||||
|
||||
// ServerBlockStorage is used by a directive's
|
||||
// setup function to persist state between all
|
||||
// the keys on a server block.
|
||||
ServerBlockStorage interface{}
|
||||
}
|
||||
|
||||
// ServerType gets the name of the server type that is being set up.
|
||||
func (c *Controller) ServerType() string {
|
||||
return c.instance.serverType
|
||||
}
|
||||
|
||||
// OnFirstStartup adds fn to the list of callback functions to execute
|
||||
// when the server is about to be started NOT as part of a restart.
|
||||
func (c *Controller) OnFirstStartup(fn func() error) {
|
||||
c.instance.OnFirstStartup = append(c.instance.OnFirstStartup, fn)
|
||||
}
|
||||
|
||||
// OnStartup adds fn to the list of callback functions to execute
|
||||
// when the server is about to be started (including restarts).
|
||||
func (c *Controller) OnStartup(fn func() error) {
|
||||
c.instance.OnStartup = append(c.instance.OnStartup, fn)
|
||||
}
|
||||
|
||||
// OnRestart adds fn to the list of callback functions to execute
|
||||
// when the server is about to be restarted.
|
||||
func (c *Controller) OnRestart(fn func() error) {
|
||||
c.instance.OnRestart = append(c.instance.OnRestart, fn)
|
||||
}
|
||||
|
||||
// OnRestartFailed adds fn to the list of callback functions to execute
|
||||
// if the server failed to restart.
|
||||
func (c *Controller) OnRestartFailed(fn func() error) {
|
||||
c.instance.OnRestartFailed = append(c.instance.OnRestartFailed, fn)
|
||||
}
|
||||
|
||||
// OnShutdown adds fn to the list of callback functions to execute
|
||||
// when the server is about to be shut down (including restarts).
|
||||
func (c *Controller) OnShutdown(fn func() error) {
|
||||
c.instance.OnShutdown = append(c.instance.OnShutdown, fn)
|
||||
}
|
||||
|
||||
// OnFinalShutdown adds fn to the list of callback functions to execute
|
||||
// when the server is about to be shut down NOT as part of a restart.
|
||||
func (c *Controller) OnFinalShutdown(fn func() error) {
|
||||
c.instance.OnFinalShutdown = append(c.instance.OnFinalShutdown, fn)
|
||||
}
|
||||
|
||||
// Context gets the context associated with the instance associated with c.
|
||||
func (c *Controller) Context() Context {
|
||||
return c.instance.context
|
||||
}
|
||||
|
||||
// Get safely gets a value from the Instance's storage.
|
||||
func (c *Controller) Get(key interface{}) interface{} {
|
||||
c.instance.StorageMu.RLock()
|
||||
defer c.instance.StorageMu.RUnlock()
|
||||
return c.instance.Storage[key]
|
||||
}
|
||||
|
||||
// Set safely sets a value on the Instance's storage.
|
||||
func (c *Controller) Set(key, val interface{}) {
|
||||
c.instance.StorageMu.Lock()
|
||||
c.instance.Storage[key] = val
|
||||
c.instance.StorageMu.Unlock()
|
||||
}
|
||||
|
||||
// NewTestController creates a new Controller for
|
||||
// the server type and input specified. The filename
|
||||
// is "Testfile". If the server type is not empty and
|
||||
// is plugged in, a context will be created so that
|
||||
// the results of setup functions can be checked for
|
||||
// correctness.
|
||||
//
|
||||
// Used only for testing, but exported so plugins can
|
||||
// use this for convenience.
|
||||
func NewTestController(serverType, input string) *Controller {
|
||||
testInst := &Instance{serverType: serverType, Storage: make(map[interface{}]interface{})}
|
||||
if stype, err := getServerType(serverType); err == nil {
|
||||
testInst.context = stype.NewContext(testInst)
|
||||
}
|
||||
return &Controller{
|
||||
instance: testInst,
|
||||
Dispenser: caddyfile.NewDispenser("Testfile", strings.NewReader(input)),
|
||||
OncePerServerBlock: func(f func() error) error { return f() },
|
||||
}
|
||||
}
|
470
vendor/github.com/coredns/caddy/plugins.go
generated
vendored
Normal file
470
vendor/github.com/coredns/caddy/plugins.go
generated
vendored
Normal file
@@ -0,0 +1,470 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package caddy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/coredns/caddy/caddyfile"
|
||||
)
|
||||
|
||||
// These are all the registered plugins.
|
||||
var (
|
||||
// serverTypes is a map of registered server types.
|
||||
serverTypes = make(map[string]ServerType)
|
||||
|
||||
// plugins is a map of server type to map of plugin name to
|
||||
// Plugin. These are the "general" plugins that may or may
|
||||
// not be associated with a specific server type. If it's
|
||||
// applicable to multiple server types or the server type is
|
||||
// irrelevant, the key is empty string (""). But all plugins
|
||||
// must have a name.
|
||||
plugins = make(map[string]map[string]Plugin)
|
||||
|
||||
// eventHooks is a map of hook name to Hook. All hooks plugins
|
||||
// must have a name.
|
||||
eventHooks = &sync.Map{}
|
||||
|
||||
// parsingCallbacks maps server type to map of directive
|
||||
// to list of callback functions. These aren't really
|
||||
// plugins on their own, but are often registered from
|
||||
// plugins.
|
||||
parsingCallbacks = make(map[string]map[string][]ParsingCallback)
|
||||
|
||||
// caddyfileLoaders is the list of all Caddyfile loaders
|
||||
// in registration order.
|
||||
caddyfileLoaders []caddyfileLoader
|
||||
)
|
||||
|
||||
// DescribePlugins returns a string describing the registered plugins.
|
||||
func DescribePlugins() string {
|
||||
pl := ListPlugins()
|
||||
|
||||
str := "Server types:\n"
|
||||
for _, name := range pl["server_types"] {
|
||||
str += " " + name + "\n"
|
||||
}
|
||||
|
||||
str += "\nCaddyfile loaders:\n"
|
||||
for _, name := range pl["caddyfile_loaders"] {
|
||||
str += " " + name + "\n"
|
||||
}
|
||||
|
||||
if len(pl["event_hooks"]) > 0 {
|
||||
str += "\nEvent hook plugins:\n"
|
||||
for _, name := range pl["event_hooks"] {
|
||||
str += " hook." + name + "\n"
|
||||
}
|
||||
}
|
||||
|
||||
if len(pl["clustering"]) > 0 {
|
||||
str += "\nClustering plugins:\n"
|
||||
for _, name := range pl["clustering"] {
|
||||
str += " " + name + "\n"
|
||||
}
|
||||
}
|
||||
|
||||
str += "\nOther plugins:\n"
|
||||
for _, name := range pl["others"] {
|
||||
str += " " + name + "\n"
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// ListPlugins makes a list of the registered plugins,
|
||||
// keyed by plugin type.
|
||||
func ListPlugins() map[string][]string {
|
||||
p := make(map[string][]string)
|
||||
|
||||
// server type plugins
|
||||
for name := range serverTypes {
|
||||
p["server_types"] = append(p["server_types"], name)
|
||||
}
|
||||
|
||||
// caddyfile loaders in registration order
|
||||
for _, loader := range caddyfileLoaders {
|
||||
p["caddyfile_loaders"] = append(p["caddyfile_loaders"], loader.name)
|
||||
}
|
||||
if defaultCaddyfileLoader.name != "" {
|
||||
p["caddyfile_loaders"] = append(p["caddyfile_loaders"], defaultCaddyfileLoader.name)
|
||||
}
|
||||
|
||||
// List the event hook plugins
|
||||
eventHooks.Range(func(k, _ interface{}) bool {
|
||||
p["event_hooks"] = append(p["event_hooks"], k.(string))
|
||||
return true
|
||||
})
|
||||
|
||||
// alphabetize the rest of the plugins
|
||||
var others []string
|
||||
for stype, stypePlugins := range plugins {
|
||||
for name := range stypePlugins {
|
||||
var s string
|
||||
if stype != "" {
|
||||
s = stype + "."
|
||||
}
|
||||
s += name
|
||||
others = append(others, s)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(others)
|
||||
for _, name := range others {
|
||||
p["others"] = append(p["others"], name)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// ValidDirectives returns the list of all directives that are
|
||||
// recognized for the server type serverType. However, not all
|
||||
// directives may be installed. This makes it possible to give
|
||||
// more helpful error messages, like "did you mean ..." or
|
||||
// "maybe you need to plug in ...".
|
||||
func ValidDirectives(serverType string) []string {
|
||||
stype, err := getServerType(serverType)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return stype.Directives()
|
||||
}
|
||||
|
||||
// ServerListener pairs a server to its listener and/or packetconn.
|
||||
type ServerListener struct {
|
||||
server Server
|
||||
listener net.Listener
|
||||
packet net.PacketConn
|
||||
}
|
||||
|
||||
// LocalAddr returns the local network address of the packetconn. It returns
|
||||
// nil when it is not set.
|
||||
func (s ServerListener) LocalAddr() net.Addr {
|
||||
if s.packet == nil {
|
||||
return nil
|
||||
}
|
||||
return s.packet.LocalAddr()
|
||||
}
|
||||
|
||||
// Addr returns the listener's network address. It returns nil when it is
|
||||
// not set.
|
||||
func (s ServerListener) Addr() net.Addr {
|
||||
if s.listener == nil {
|
||||
return nil
|
||||
}
|
||||
return s.listener.Addr()
|
||||
}
|
||||
|
||||
// Context is a type which carries a server type through
|
||||
// the load and setup phase; it maintains the state
|
||||
// between loading the Caddyfile, then executing its
|
||||
// directives, then making the servers for Caddy to
|
||||
// manage. Typically, such state involves configuration
|
||||
// structs, etc.
|
||||
type Context interface {
|
||||
// Called after the Caddyfile is parsed into server
|
||||
// blocks but before the directives are executed,
|
||||
// this method gives you an opportunity to inspect
|
||||
// the server blocks and prepare for the execution
|
||||
// of directives. Return the server blocks (which
|
||||
// you may modify, if desired) and an error, if any.
|
||||
// The first argument is the name or path to the
|
||||
// configuration file (Caddyfile).
|
||||
//
|
||||
// This function can be a no-op and simply return its
|
||||
// input if there is nothing to do here.
|
||||
InspectServerBlocks(string, []caddyfile.ServerBlock) ([]caddyfile.ServerBlock, error)
|
||||
|
||||
// This is what Caddy calls to make server instances.
|
||||
// By this time, all directives have been executed and,
|
||||
// presumably, the context has enough state to produce
|
||||
// server instances for Caddy to start.
|
||||
MakeServers() ([]Server, error)
|
||||
}
|
||||
|
||||
// RegisterServerType registers a server type srv by its
|
||||
// name, typeName.
|
||||
func RegisterServerType(typeName string, srv ServerType) {
|
||||
if _, ok := serverTypes[typeName]; ok {
|
||||
panic("server type already registered")
|
||||
}
|
||||
serverTypes[typeName] = srv
|
||||
}
|
||||
|
||||
// ServerType contains information about a server type.
|
||||
type ServerType struct {
|
||||
// Function that returns the list of directives, in
|
||||
// execution order, that are valid for this server
|
||||
// type. Directives should be one word if possible
|
||||
// and lower-cased.
|
||||
Directives func() []string
|
||||
|
||||
// DefaultInput returns a default config input if none
|
||||
// is otherwise loaded. This is optional, but highly
|
||||
// recommended, otherwise a blank Caddyfile will be
|
||||
// used.
|
||||
DefaultInput func() Input
|
||||
|
||||
// The function that produces a new server type context.
|
||||
// This will be called when a new Caddyfile is being
|
||||
// loaded, parsed, and executed independently of any
|
||||
// startup phases before this one. It's a way to keep
|
||||
// each set of server instances separate and to reduce
|
||||
// the amount of global state you need.
|
||||
NewContext func(inst *Instance) Context
|
||||
}
|
||||
|
||||
// Plugin is a type which holds information about a plugin.
|
||||
type Plugin struct {
|
||||
// ServerType is the type of server this plugin is for.
|
||||
// Can be empty if not applicable, or if the plugin
|
||||
// can associate with any server type.
|
||||
ServerType string
|
||||
|
||||
// Action is the plugin's setup function, if associated
|
||||
// with a directive in the Caddyfile.
|
||||
Action SetupFunc
|
||||
}
|
||||
|
||||
// RegisterPlugin plugs in plugin. All plugins should register
|
||||
// themselves, even if they do not perform an action associated
|
||||
// with a directive. It is important for the process to know
|
||||
// which plugins are available.
|
||||
//
|
||||
// The plugin MUST have a name: lower case and one word.
|
||||
// If this plugin has an action, it must be the name of
|
||||
// the directive that invokes it. A name is always required
|
||||
// and must be unique for the server type.
|
||||
func RegisterPlugin(name string, plugin Plugin) {
|
||||
if name == "" {
|
||||
panic("plugin must have a name")
|
||||
}
|
||||
if _, ok := plugins[plugin.ServerType]; !ok {
|
||||
plugins[plugin.ServerType] = make(map[string]Plugin)
|
||||
}
|
||||
if _, dup := plugins[plugin.ServerType][name]; dup {
|
||||
panic("plugin named " + name + " already registered for server type " + plugin.ServerType)
|
||||
}
|
||||
plugins[plugin.ServerType][name] = plugin
|
||||
}
|
||||
|
||||
// EventName represents the name of an event used with event hooks.
|
||||
type EventName string
|
||||
|
||||
// Define names for the various events
|
||||
const (
|
||||
StartupEvent EventName = "startup"
|
||||
ShutdownEvent = "shutdown"
|
||||
CertRenewEvent = "certrenew"
|
||||
InstanceStartupEvent = "instancestartup"
|
||||
InstanceRestartEvent = "instancerestart"
|
||||
)
|
||||
|
||||
// EventHook is a type which holds information about a startup hook plugin.
|
||||
type EventHook func(eventType EventName, eventInfo interface{}) error
|
||||
|
||||
// RegisterEventHook plugs in hook. All the hooks should register themselves
|
||||
// and they must have a name.
|
||||
func RegisterEventHook(name string, hook EventHook) {
|
||||
if name == "" {
|
||||
panic("event hook must have a name")
|
||||
}
|
||||
_, dup := eventHooks.LoadOrStore(name, hook)
|
||||
if dup {
|
||||
panic("hook named " + name + " already registered")
|
||||
}
|
||||
}
|
||||
|
||||
// EmitEvent executes the different hooks passing the EventType as an
|
||||
// argument. This is a blocking function. Hook developers should
|
||||
// use 'go' keyword if they don't want to block Caddy.
|
||||
func EmitEvent(event EventName, info interface{}) {
|
||||
eventHooks.Range(func(k, v interface{}) bool {
|
||||
err := v.(EventHook)(event, info)
|
||||
if err != nil {
|
||||
log.Printf("error on '%s' hook: %v", k.(string), err)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// cloneEventHooks return a clone of the event hooks *sync.Map
|
||||
func cloneEventHooks() *sync.Map {
|
||||
c := &sync.Map{}
|
||||
eventHooks.Range(func(k, v interface{}) bool {
|
||||
c.Store(k, v)
|
||||
return true
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
// purgeEventHooks purges all event hooks from the map
|
||||
func purgeEventHooks() {
|
||||
eventHooks.Range(func(k, _ interface{}) bool {
|
||||
eventHooks.Delete(k)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// restoreEventHooks restores eventHooks with a provided *sync.Map
|
||||
func restoreEventHooks(m *sync.Map) {
|
||||
// Purge old event hooks
|
||||
purgeEventHooks()
|
||||
|
||||
// Restore event hooks
|
||||
m.Range(func(k, v interface{}) bool {
|
||||
eventHooks.Store(k, v)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// ParsingCallback is a function that is called after
|
||||
// a directive's setup functions have been executed
|
||||
// for all the server blocks.
|
||||
type ParsingCallback func(Context) error
|
||||
|
||||
// RegisterParsingCallback registers callback to be called after
|
||||
// executing the directive afterDir for server type serverType.
|
||||
func RegisterParsingCallback(serverType, afterDir string, callback ParsingCallback) {
|
||||
if _, ok := parsingCallbacks[serverType]; !ok {
|
||||
parsingCallbacks[serverType] = make(map[string][]ParsingCallback)
|
||||
}
|
||||
parsingCallbacks[serverType][afterDir] = append(parsingCallbacks[serverType][afterDir], callback)
|
||||
}
|
||||
|
||||
// SetupFunc is used to set up a plugin, or in other words,
|
||||
// execute a directive. It will be called once per key for
|
||||
// each server block it appears in.
|
||||
type SetupFunc func(c *Controller) error
|
||||
|
||||
// DirectiveAction gets the action for directive dir of
|
||||
// server type serverType.
|
||||
func DirectiveAction(serverType, dir string) (SetupFunc, error) {
|
||||
if stypePlugins, ok := plugins[serverType]; ok {
|
||||
if plugin, ok := stypePlugins[dir]; ok {
|
||||
return plugin.Action, nil
|
||||
}
|
||||
}
|
||||
if genericPlugins, ok := plugins[""]; ok {
|
||||
if plugin, ok := genericPlugins[dir]; ok {
|
||||
return plugin.Action, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("no action found for directive '%s' with server type '%s' (missing a plugin?)",
|
||||
dir, serverType)
|
||||
}
|
||||
|
||||
// Loader is a type that can load a Caddyfile.
|
||||
// It is passed the name of the server type.
|
||||
// It returns an error only if something went
|
||||
// wrong, not simply if there is no Caddyfile
|
||||
// for this loader to load.
|
||||
//
|
||||
// A Loader should only load the Caddyfile if
|
||||
// a certain condition or requirement is met,
|
||||
// as returning a non-nil Input value along with
|
||||
// another Loader will result in an error.
|
||||
// In other words, loading the Caddyfile must
|
||||
// be deliberate & deterministic, not haphazard.
|
||||
//
|
||||
// The exception is the default Caddyfile loader,
|
||||
// which will be called only if no other Caddyfile
|
||||
// loaders return a non-nil Input. The default
|
||||
// loader may always return an Input value.
|
||||
type Loader interface {
|
||||
Load(serverType string) (Input, error)
|
||||
}
|
||||
|
||||
// LoaderFunc is a convenience type similar to http.HandlerFunc
|
||||
// that allows you to use a plain function as a Load() method.
|
||||
type LoaderFunc func(serverType string) (Input, error)
|
||||
|
||||
// Load loads a Caddyfile.
|
||||
func (lf LoaderFunc) Load(serverType string) (Input, error) {
|
||||
return lf(serverType)
|
||||
}
|
||||
|
||||
// RegisterCaddyfileLoader registers loader named name.
|
||||
func RegisterCaddyfileLoader(name string, loader Loader) {
|
||||
caddyfileLoaders = append(caddyfileLoaders, caddyfileLoader{name: name, loader: loader})
|
||||
}
|
||||
|
||||
// SetDefaultCaddyfileLoader registers loader by name
|
||||
// as the default Caddyfile loader if no others produce
|
||||
// a Caddyfile. If another Caddyfile loader has already
|
||||
// been set as the default, this replaces it.
|
||||
//
|
||||
// Do not call RegisterCaddyfileLoader on the same
|
||||
// loader; that would be redundant.
|
||||
func SetDefaultCaddyfileLoader(name string, loader Loader) {
|
||||
defaultCaddyfileLoader = caddyfileLoader{name: name, loader: loader}
|
||||
}
|
||||
|
||||
// loadCaddyfileInput iterates the registered Caddyfile loaders
|
||||
// and, if needed, calls the default loader, to load a Caddyfile.
|
||||
// It is an error if any of the loaders return an error or if
|
||||
// more than one loader returns a Caddyfile.
|
||||
func loadCaddyfileInput(serverType string) (Input, error) {
|
||||
var loadedBy string
|
||||
var caddyfileToUse Input
|
||||
for _, l := range caddyfileLoaders {
|
||||
cdyfile, err := l.loader.Load(serverType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading Caddyfile via %s: %v", l.name, err)
|
||||
}
|
||||
if cdyfile != nil {
|
||||
if caddyfileToUse != nil {
|
||||
return nil, fmt.Errorf("Caddyfile loaded multiple times; first by %s, then by %s", loadedBy, l.name)
|
||||
}
|
||||
loaderUsed = l
|
||||
caddyfileToUse = cdyfile
|
||||
loadedBy = l.name
|
||||
}
|
||||
}
|
||||
if caddyfileToUse == nil && defaultCaddyfileLoader.loader != nil {
|
||||
cdyfile, err := defaultCaddyfileLoader.loader.Load(serverType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cdyfile != nil {
|
||||
loaderUsed = defaultCaddyfileLoader
|
||||
caddyfileToUse = cdyfile
|
||||
}
|
||||
}
|
||||
return caddyfileToUse, nil
|
||||
}
|
||||
|
||||
// OnProcessExit is a list of functions to run when the process
|
||||
// exits -- they are ONLY for cleanup and should not block,
|
||||
// return errors, or do anything fancy. They will be run with
|
||||
// every signal, even if "shutdown callbacks" are not executed.
|
||||
// This variable must only be modified in the main goroutine
|
||||
// from init() functions.
|
||||
var OnProcessExit []func()
|
||||
|
||||
// caddyfileLoader pairs the name of a loader to the loader.
|
||||
type caddyfileLoader struct {
|
||||
name string
|
||||
loader Loader
|
||||
}
|
||||
|
||||
var (
|
||||
defaultCaddyfileLoader caddyfileLoader // the default loader if all else fail
|
||||
loaderUsed caddyfileLoader // the loader that was used (relevant for reloads)
|
||||
)
|
22
vendor/github.com/coredns/caddy/rlimit_nonposix.go
generated
vendored
Normal file
22
vendor/github.com/coredns/caddy/rlimit_nonposix.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build windows plan9 nacl js
|
||||
|
||||
package caddy
|
||||
|
||||
// checkFdlimit issues a warning if the OS limit for
|
||||
// max file descriptors is below a recommended minimum.
|
||||
func checkFdlimit() {
|
||||
}
|
37
vendor/github.com/coredns/caddy/rlimit_posix.go
generated
vendored
Normal file
37
vendor/github.com/coredns/caddy/rlimit_posix.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !windows,!plan9,!nacl,!js
|
||||
|
||||
package caddy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// checkFdlimit issues a warning if the OS limit for
|
||||
// max file descriptors is below a recommended minimum.
|
||||
func checkFdlimit() {
|
||||
const min = 8192
|
||||
|
||||
// Warn if ulimit is too low for production sites
|
||||
rlimit := &syscall.Rlimit{}
|
||||
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, rlimit)
|
||||
if err == nil && rlimit.Cur < min {
|
||||
fmt.Printf("WARNING: File descriptor limit %d is too low for production servers. "+
|
||||
"At least %d is recommended. Fix with `ulimit -n %d`.\n", rlimit.Cur, min, min)
|
||||
}
|
||||
|
||||
}
|
103
vendor/github.com/coredns/caddy/sigtrap.go
generated
vendored
Normal file
103
vendor/github.com/coredns/caddy/sigtrap.go
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package caddy
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// TrapSignals create signal handlers for all applicable signals for this
|
||||
// system. If your Go program uses signals, this is a rather invasive
|
||||
// function; best to implement them yourself in that case. Signals are not
|
||||
// required for the caddy package to function properly, but this is a
|
||||
// convenient way to allow the user to control this part of your program.
|
||||
func TrapSignals() {
|
||||
trapSignalsCrossPlatform()
|
||||
trapSignalsPosix()
|
||||
}
|
||||
|
||||
// trapSignalsCrossPlatform captures SIGINT, which triggers forceful
|
||||
// shutdown that executes shutdown callbacks first. A second interrupt
|
||||
// signal will exit the process immediately.
|
||||
func trapSignalsCrossPlatform() {
|
||||
go func() {
|
||||
shutdown := make(chan os.Signal, 1)
|
||||
signal.Notify(shutdown, os.Interrupt)
|
||||
|
||||
for i := 0; true; i++ {
|
||||
<-shutdown
|
||||
|
||||
if i > 0 {
|
||||
log.Println("[INFO] SIGINT: Force quit")
|
||||
for _, f := range OnProcessExit {
|
||||
f() // important cleanup actions only
|
||||
}
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
log.Println("[INFO] SIGINT: Shutting down")
|
||||
|
||||
// important cleanup actions before shutdown callbacks
|
||||
for _, f := range OnProcessExit {
|
||||
f()
|
||||
}
|
||||
|
||||
go func() {
|
||||
os.Exit(executeShutdownCallbacks("SIGINT"))
|
||||
}()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// executeShutdownCallbacks executes the shutdown callbacks as initiated
|
||||
// by signame. It logs any errors and returns the recommended exit status.
|
||||
// This function is idempotent; subsequent invocations always return 0.
|
||||
func executeShutdownCallbacks(signame string) (exitCode int) {
|
||||
shutdownCallbacksOnce.Do(func() {
|
||||
// execute third-party shutdown hooks
|
||||
EmitEvent(ShutdownEvent, signame)
|
||||
|
||||
errs := allShutdownCallbacks()
|
||||
if len(errs) > 0 {
|
||||
for _, err := range errs {
|
||||
log.Printf("[ERROR] %s shutdown: %v", signame, err)
|
||||
}
|
||||
exitCode = 4
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// allShutdownCallbacks executes all the shutdown callbacks
|
||||
// for all the instances, and returns all the errors generated
|
||||
// during their execution. An error executing one shutdown
|
||||
// callback does not stop execution of others. Only one shutdown
|
||||
// callback is executed at a time.
|
||||
func allShutdownCallbacks() []error {
|
||||
var errs []error
|
||||
instancesMu.Lock()
|
||||
for _, inst := range instances {
|
||||
errs = append(errs, inst.ShutdownCallbacks()...)
|
||||
}
|
||||
instancesMu.Unlock()
|
||||
return errs
|
||||
}
|
||||
|
||||
// shutdownCallbacksOnce ensures that shutdown callbacks
|
||||
// for all instances are only executed once.
|
||||
var shutdownCallbacksOnce sync.Once
|
19
vendor/github.com/coredns/caddy/sigtrap_nonposix.go
generated
vendored
Normal file
19
vendor/github.com/coredns/caddy/sigtrap_nonposix.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build windows plan9 nacl js
|
||||
|
||||
package caddy
|
||||
|
||||
func trapSignalsPosix() {}
|
106
vendor/github.com/coredns/caddy/sigtrap_posix.go
generated
vendored
Normal file
106
vendor/github.com/coredns/caddy/sigtrap_posix.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !windows,!plan9,!nacl,!js
|
||||
|
||||
package caddy
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// trapSignalsPosix captures POSIX-only signals.
|
||||
func trapSignalsPosix() {
|
||||
go func() {
|
||||
sigchan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigchan, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGUSR1, syscall.SIGUSR2)
|
||||
|
||||
for sig := range sigchan {
|
||||
switch sig {
|
||||
case syscall.SIGQUIT:
|
||||
log.Println("[INFO] SIGQUIT: Quitting process immediately")
|
||||
for _, f := range OnProcessExit {
|
||||
f() // only perform important cleanup actions
|
||||
}
|
||||
os.Exit(0)
|
||||
|
||||
case syscall.SIGTERM:
|
||||
log.Println("[INFO] SIGTERM: Shutting down servers then terminating")
|
||||
exitCode := executeShutdownCallbacks("SIGTERM")
|
||||
for _, f := range OnProcessExit {
|
||||
f() // only perform important cleanup actions
|
||||
}
|
||||
err := Stop()
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] SIGTERM stop: %v", err)
|
||||
exitCode = 3
|
||||
}
|
||||
|
||||
os.Exit(exitCode)
|
||||
|
||||
case syscall.SIGUSR1:
|
||||
log.Println("[INFO] SIGUSR1: Reloading")
|
||||
|
||||
// Start with the existing Caddyfile
|
||||
caddyfileToUse, inst, err := getCurrentCaddyfile()
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] SIGUSR1: %v", err)
|
||||
continue
|
||||
}
|
||||
if loaderUsed.loader == nil {
|
||||
// This also should never happen
|
||||
log.Println("[ERROR] SIGUSR1: no Caddyfile loader with which to reload Caddyfile")
|
||||
continue
|
||||
}
|
||||
|
||||
// Load the updated Caddyfile
|
||||
newCaddyfile, err := loaderUsed.loader.Load(inst.serverType)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] SIGUSR1: loading updated Caddyfile: %v", err)
|
||||
continue
|
||||
}
|
||||
if newCaddyfile != nil {
|
||||
caddyfileToUse = newCaddyfile
|
||||
}
|
||||
|
||||
// Backup old event hooks
|
||||
oldEventHooks := cloneEventHooks()
|
||||
|
||||
// Purge the old event hooks
|
||||
purgeEventHooks()
|
||||
|
||||
// Kick off the restart; our work is done
|
||||
EmitEvent(InstanceRestartEvent, nil)
|
||||
_, err = inst.Restart(caddyfileToUse)
|
||||
if err != nil {
|
||||
restoreEventHooks(oldEventHooks)
|
||||
|
||||
log.Printf("[ERROR] SIGUSR1: %v", err)
|
||||
}
|
||||
|
||||
case syscall.SIGUSR2:
|
||||
log.Println("[INFO] SIGUSR2: Upgrading")
|
||||
if err := Upgrade(); err != nil {
|
||||
log.Printf("[ERROR] SIGUSR2: upgrading: %v", err)
|
||||
}
|
||||
|
||||
case syscall.SIGHUP:
|
||||
// ignore; this signal is sometimes sent outside of the user's control
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
232
vendor/github.com/coredns/caddy/upgrade.go
generated
vendored
Normal file
232
vendor/github.com/coredns/caddy/upgrade.go
generated
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package caddy
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// register CaddyfileInput with gob so it knows into
|
||||
// which concrete type to decode an Input interface
|
||||
gob.Register(CaddyfileInput{})
|
||||
}
|
||||
|
||||
// IsUpgrade returns true if this process is part of an upgrade
|
||||
// where a parent caddy process spawned this one to upgrade
|
||||
// the binary.
|
||||
func IsUpgrade() bool {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
return isUpgrade
|
||||
}
|
||||
|
||||
// Upgrade re-launches the process, preserving the listeners
|
||||
// for a graceful upgrade. It does NOT load new configuration;
|
||||
// it only starts the process anew with the current config.
|
||||
// This makes it possible to perform zero-downtime binary upgrades.
|
||||
//
|
||||
// TODO: For more information when debugging, see:
|
||||
// https://forum.golangbridge.org/t/bind-address-already-in-use-even-after-listener-closed/1510?u=matt
|
||||
// https://github.com/mholt/shared-conn
|
||||
func Upgrade() error {
|
||||
log.Println("[INFO] Upgrading")
|
||||
|
||||
// use existing Caddyfile; do not change configuration during upgrade
|
||||
currentCaddyfile, _, err := getCurrentCaddyfile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(os.Args) == 0 { // this should never happen, but...
|
||||
os.Args = []string{""}
|
||||
}
|
||||
|
||||
// tell the child that it's a restart
|
||||
env := os.Environ()
|
||||
if !IsUpgrade() {
|
||||
env = append(env, "CADDY__UPGRADE=1")
|
||||
}
|
||||
|
||||
// prepare our payload to the child process
|
||||
cdyfileGob := transferGob{
|
||||
ListenerFds: make(map[string]uintptr),
|
||||
Caddyfile: currentCaddyfile,
|
||||
}
|
||||
|
||||
// prepare a pipe to the fork's stdin so it can get the Caddyfile
|
||||
rpipe, wpipe, err := os.Pipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// prepare a pipe that the child process will use to communicate
|
||||
// its success with us by sending > 0 bytes
|
||||
sigrpipe, sigwpipe, err := os.Pipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// pass along relevant file descriptors to child process; ordering
|
||||
// is very important since we rely on these being in certain positions.
|
||||
extraFiles := []*os.File{sigwpipe} // fd 3
|
||||
|
||||
// add file descriptors of all the sockets
|
||||
for i, j := 0, 0; ; i++ {
|
||||
instancesMu.Lock()
|
||||
if i >= len(instances) {
|
||||
instancesMu.Unlock()
|
||||
break
|
||||
}
|
||||
inst := instances[i]
|
||||
instancesMu.Unlock()
|
||||
|
||||
for _, s := range inst.servers {
|
||||
gs, gracefulOk := s.server.(GracefulServer)
|
||||
ln, lnOk := s.listener.(Listener)
|
||||
pc, pcOk := s.packet.(PacketConn)
|
||||
if gracefulOk {
|
||||
if lnOk {
|
||||
lnFile, _ := ln.File()
|
||||
extraFiles = append(extraFiles, lnFile)
|
||||
cdyfileGob.ListenerFds["tcp"+gs.Address()] = uintptr(4 + j) // 4 fds come before any of the listeners
|
||||
j++
|
||||
}
|
||||
if pcOk {
|
||||
pcFile, _ := pc.File()
|
||||
extraFiles = append(extraFiles, pcFile)
|
||||
cdyfileGob.ListenerFds["udp"+gs.Address()] = uintptr(4 + j) // 4 fds come before any of the listeners
|
||||
j++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set up the command
|
||||
cmd := exec.Command(os.Args[0], os.Args[1:]...)
|
||||
cmd.Stdin = rpipe // fd 0
|
||||
cmd.Stdout = os.Stdout // fd 1
|
||||
cmd.Stderr = os.Stderr // fd 2
|
||||
cmd.ExtraFiles = extraFiles
|
||||
cmd.Env = env
|
||||
|
||||
// spawn the child process
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// immediately close our dup'ed fds and the write end of our signal pipe
|
||||
for _, f := range extraFiles {
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// feed Caddyfile to the child
|
||||
err = gob.NewEncoder(wpipe).Encode(cdyfileGob)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = wpipe.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// determine whether child startup succeeded
|
||||
answer, readErr := ioutil.ReadAll(sigrpipe)
|
||||
if len(answer) == 0 {
|
||||
cmdErr := cmd.Wait() // get exit status
|
||||
errStr := fmt.Sprintf("child failed to initialize: %v", cmdErr)
|
||||
if readErr != nil {
|
||||
errStr += fmt.Sprintf(" - additionally, error communicating with child process: %v", readErr)
|
||||
}
|
||||
return fmt.Errorf(errStr)
|
||||
}
|
||||
|
||||
// looks like child is successful; we can exit gracefully.
|
||||
log.Println("[INFO] Upgrade finished")
|
||||
return Stop()
|
||||
}
|
||||
|
||||
// getCurrentCaddyfile gets the Caddyfile used by the
|
||||
// current (first) Instance and returns both of them.
|
||||
func getCurrentCaddyfile() (Input, *Instance, error) {
|
||||
instancesMu.Lock()
|
||||
if len(instances) == 0 {
|
||||
instancesMu.Unlock()
|
||||
return nil, nil, fmt.Errorf("no server instances are fully running")
|
||||
}
|
||||
inst := instances[0]
|
||||
instancesMu.Unlock()
|
||||
|
||||
currentCaddyfile := inst.caddyfileInput
|
||||
if currentCaddyfile == nil {
|
||||
// hmm, did spawning process forget to close stdin? Anyhow, this is unusual.
|
||||
return nil, inst, fmt.Errorf("no Caddyfile to reload (was stdin left open?)")
|
||||
}
|
||||
return currentCaddyfile, inst, nil
|
||||
}
|
||||
|
||||
// signalSuccessToParent tells the parent our status using pipe at index 3.
|
||||
// If this process is not a restart, this function does nothing.
|
||||
// Calling this function once this process has successfully initialized
|
||||
// is vital so that the parent process can unblock and kill itself.
|
||||
// This function is idempotent; it executes at most once per process.
|
||||
func signalSuccessToParent() {
|
||||
signalParentOnce.Do(func() {
|
||||
if IsUpgrade() {
|
||||
ppipe := os.NewFile(3, "") // parent is reading from pipe at index 3
|
||||
_, err := ppipe.Write([]byte("success")) // we must send some bytes to the parent
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Communicating successful init to parent: %v", err)
|
||||
}
|
||||
ppipe.Close()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// signalParentOnce is used to make sure that the parent is only
|
||||
// signaled once; doing so more than once breaks whatever socket is
|
||||
// at fd 4 (TODO: the reason for this is still unclear - to reproduce,
|
||||
// call Stop() and Start() in succession at least once after a
|
||||
// restart, then try loading first host of Caddyfile in the browser
|
||||
// - this was pre-v0.9; this code and godoc is borrowed from the
|
||||
// implementation then, but I'm not sure if it's been fixed yet, as
|
||||
// of v0.10.7). Do not use this directly; call signalSuccessToParent
|
||||
// instead.
|
||||
var signalParentOnce sync.Once
|
||||
|
||||
// transferGob is used if this is a child process as part of
|
||||
// a graceful upgrade; it is used to map listeners to their
|
||||
// index in the list of inherited file descriptors. This
|
||||
// variable is not safe for concurrent access.
|
||||
var loadedGob transferGob
|
||||
|
||||
// transferGob maps bind address to index of the file descriptor
|
||||
// in the Files array passed to the child process. It also contains
|
||||
// the Caddyfile contents and any other state needed by the new process.
|
||||
// Used only during graceful upgrades.
|
||||
type transferGob struct {
|
||||
ListenerFds map[string]uintptr
|
||||
Caddyfile Input
|
||||
}
|
37
vendor/github.com/coredns/coredns/core/dnsserver/address.go
generated
vendored
37
vendor/github.com/coredns/coredns/core/dnsserver/address.go
generated
vendored
@@ -4,20 +4,13 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/pkg/parse"
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
type zoneAddr struct {
|
||||
Zone string
|
||||
Port string
|
||||
Transport string // dns, tls or grpc
|
||||
IPNet *net.IPNet // if reverse zone this hold the IPNet
|
||||
Address string // used for bound zoneAddr - validation of overlapping
|
||||
Transport string // dns, tls or grpc
|
||||
Address string // used for bound zoneAddr - validation of overlapping
|
||||
}
|
||||
|
||||
// String returns the string representation of z.
|
||||
@@ -29,32 +22,6 @@ func (z zoneAddr) String() string {
|
||||
return s
|
||||
}
|
||||
|
||||
// normalizeZone parses a zone string into a structured format with separate
|
||||
// host, and port portions, as well as the original input string.
|
||||
func normalizeZone(str string) (zoneAddr, error) {
|
||||
trans, str := parse.Transport(str)
|
||||
|
||||
host, port, ipnet, err := plugin.SplitHostPort(str)
|
||||
if err != nil {
|
||||
return zoneAddr{}, err
|
||||
}
|
||||
|
||||
if port == "" {
|
||||
switch trans {
|
||||
case transport.DNS:
|
||||
port = Port
|
||||
case transport.TLS:
|
||||
port = transport.TLSPort
|
||||
case transport.GRPC:
|
||||
port = transport.GRPCPort
|
||||
case transport.HTTPS:
|
||||
port = transport.HTTPSPort
|
||||
}
|
||||
}
|
||||
|
||||
return zoneAddr{Zone: dns.Fqdn(host), Port: port, Transport: trans, IPNet: ipnet}, nil
|
||||
}
|
||||
|
||||
// SplitProtocolHostPort splits a full formed address like "dns://[::1]:53" into parts.
|
||||
func SplitProtocolHostPort(address string) (protocol string, ip string, port string, err error) {
|
||||
parts := strings.Split(address, "://")
|
||||
|
18
vendor/github.com/coredns/coredns/core/dnsserver/config.go
generated
vendored
18
vendor/github.com/coredns/coredns/core/dnsserver/config.go
generated
vendored
@@ -3,10 +3,10 @@ package dnsserver
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/coredns/coredns/plugin"
|
||||
|
||||
"github.com/caddyserver/caddy"
|
||||
)
|
||||
|
||||
// Config configuration for a single server.
|
||||
@@ -32,10 +32,10 @@ type Config struct {
|
||||
// DNS-over-TLS or DNS-over-gRPC.
|
||||
Transport string
|
||||
|
||||
// If this function is not nil it will be used to further filter access
|
||||
// to this handler. The primary use is to limit access to a reverse zone
|
||||
// on a non-octet boundary, i.e. /17
|
||||
FilterFunc func(string) bool
|
||||
// If this function is not nil it will be used to inspect and validate
|
||||
// HTTP requests. Although this isn't referenced in-tree, external plugins
|
||||
// may depend on it.
|
||||
HTTPRequestValidateFunc func(*http.Request) bool
|
||||
|
||||
// TLSConfig when listening for encrypted connections (gRPC, DNS-over-TLS).
|
||||
TLSConfig *tls.Config
|
||||
@@ -50,9 +50,13 @@ type Config struct {
|
||||
// on them should register themselves here. The name should be the name as return by the
|
||||
// Handler's Name method.
|
||||
registry map[string]plugin.Handler
|
||||
|
||||
// firstConfigInBlock is used to reference the first config in a server block, for the
|
||||
// purpose of sharing single instance of each plugin among all zones in a server block.
|
||||
firstConfigInBlock *Config
|
||||
}
|
||||
|
||||
// keyForConfig build a key for identifying the configs during setup time
|
||||
// keyForConfig builds a key for identifying the configs during setup time
|
||||
func keyForConfig(blocIndex int, blocKeyIndex int) string {
|
||||
return fmt.Sprintf("%d:%d", blocIndex, blocKeyIndex)
|
||||
}
|
||||
|
7
vendor/github.com/coredns/coredns/core/dnsserver/https.go
generated
vendored
7
vendor/github.com/coredns/coredns/core/dnsserver/https.go
generated
vendored
@@ -2,6 +2,7 @@ package dnsserver
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/nonwriter"
|
||||
)
|
||||
@@ -14,6 +15,9 @@ type DoHWriter struct {
|
||||
raddr net.Addr
|
||||
// laddr is our address. This can be optionally set.
|
||||
laddr net.Addr
|
||||
|
||||
// request is the HTTP request we're currently handling.
|
||||
request *http.Request
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote address.
|
||||
@@ -21,3 +25,6 @@ func (d *DoHWriter) RemoteAddr() net.Addr { return d.raddr }
|
||||
|
||||
// LocalAddr returns the local address.
|
||||
func (d *DoHWriter) LocalAddr() net.Addr { return d.laddr }
|
||||
|
||||
// Request returns the HTTP request
|
||||
func (d *DoHWriter) Request() *http.Request { return d.request }
|
||||
|
17
vendor/github.com/coredns/coredns/core/dnsserver/onstartup.go
generated
vendored
17
vendor/github.com/coredns/coredns/core/dnsserver/onstartup.go
generated
vendored
@@ -1,14 +1,25 @@
|
||||
package dnsserver
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// startUpZones create the text that we show when starting up:
|
||||
// startUpZones creates the text that we show when starting up:
|
||||
// grpc://example.com.:1055
|
||||
// example.com.:1053 on 127.0.0.1
|
||||
func startUpZones(protocol, addr string, zones map[string]*Config) string {
|
||||
s := ""
|
||||
|
||||
for zone := range zones {
|
||||
keys := make([]string, len(zones))
|
||||
i := 0
|
||||
for k := range zones {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, zone := range keys {
|
||||
// split addr into protocol, IP and Port
|
||||
_, ip, port, err := SplitProtocolHostPort(addr)
|
||||
|
||||
|
91
vendor/github.com/coredns/coredns/core/dnsserver/register.go
generated
vendored
91
vendor/github.com/coredns/coredns/core/dnsserver/register.go
generated
vendored
@@ -4,16 +4,15 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/coredns/caddy/caddyfile"
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||
"github.com/coredns/coredns/plugin/pkg/parse"
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
|
||||
"github.com/caddyserver/caddy"
|
||||
"github.com/caddyserver/caddy/caddyfile"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
const serverType = "dns"
|
||||
@@ -22,6 +21,7 @@ const serverType = "dns"
|
||||
// wise they potentially clash with other server types.
|
||||
func init() {
|
||||
flag.StringVar(&Port, serverType+".port", DefaultPort, "Default port")
|
||||
flag.StringVar(&Port, "p", DefaultPort, "Default port")
|
||||
|
||||
caddy.RegisterServerType(serverType, caddy.ServerType{
|
||||
Directives: func() []string { return Directives },
|
||||
@@ -61,11 +61,57 @@ var _ caddy.Context = &dnsContext{}
|
||||
func (h *dnsContext) InspectServerBlocks(sourceFile string, serverBlocks []caddyfile.ServerBlock) ([]caddyfile.ServerBlock, error) {
|
||||
// Normalize and check all the zone names and check for duplicates
|
||||
for ib, s := range serverBlocks {
|
||||
// Walk the s.Keys and expand any reverse address in their proper DNS in-addr zones. If the expansions leads for
|
||||
// more than one reverse zone, replace the current value and add the rest to s.Keys.
|
||||
zoneAddrs := []zoneAddr{}
|
||||
for ik, k := range s.Keys {
|
||||
za, err := normalizeZone(k)
|
||||
trans, k1 := parse.Transport(k) // get rid of any dns:// or other scheme.
|
||||
hosts, port, err := plugin.SplitHostPort(k1)
|
||||
// We need to make this a fully qualified domain name to catch all errors here and not later when
|
||||
// plugin.Normalize is called again on these strings, with the prime difference being that the domain
|
||||
// name is fully qualified. This was found by fuzzing where "ȶ" is deemed OK, but "ȶ." is not (might be a
|
||||
// bug in miekg/dns actually). But here we were checking ȶ, which is OK, and later we barf in ȶ. leading to
|
||||
// "index out of range".
|
||||
for ih := range hosts {
|
||||
_, _, err := plugin.SplitHostPort(dns.Fqdn(hosts[ih]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if port == "" {
|
||||
switch trans {
|
||||
case transport.DNS:
|
||||
port = Port
|
||||
case transport.TLS:
|
||||
port = transport.TLSPort
|
||||
case transport.GRPC:
|
||||
port = transport.GRPCPort
|
||||
case transport.HTTPS:
|
||||
port = transport.HTTPSPort
|
||||
}
|
||||
}
|
||||
|
||||
if len(hosts) > 1 {
|
||||
s.Keys[ik] = hosts[0] + ":" + port // replace for the first
|
||||
for _, h := range hosts[1:] { // add the rest
|
||||
s.Keys = append(s.Keys, h+":"+port)
|
||||
}
|
||||
}
|
||||
for i := range hosts {
|
||||
zoneAddrs = append(zoneAddrs, zoneAddr{Zone: dns.Fqdn(hosts[i]), Port: port, Transport: trans})
|
||||
}
|
||||
}
|
||||
|
||||
serverBlocks[ib].Keys = s.Keys // important to save back the new keys that are potentially created here.
|
||||
|
||||
var firstConfigInBlock *Config
|
||||
|
||||
for ik := range s.Keys {
|
||||
za := zoneAddrs[ik]
|
||||
s.Keys[ik] = za.String()
|
||||
// Save the config to our master list, and key it for lookups.
|
||||
cfg := &Config{
|
||||
@@ -74,23 +120,16 @@ func (h *dnsContext) InspectServerBlocks(sourceFile string, serverBlocks []caddy
|
||||
Port: za.Port,
|
||||
Transport: za.Transport,
|
||||
}
|
||||
keyConfig := keyForConfig(ib, ik)
|
||||
if za.IPNet == nil {
|
||||
h.saveConfig(keyConfig, cfg)
|
||||
continue
|
||||
}
|
||||
|
||||
ones, bits := za.IPNet.Mask.Size()
|
||||
if (bits-ones)%8 != 0 { // only do this for non-octet boundaries
|
||||
cfg.FilterFunc = func(s string) bool {
|
||||
// TODO(miek): strings.ToLower! Slow and allocates new string.
|
||||
addr := dnsutil.ExtractAddressFromReverse(strings.ToLower(s))
|
||||
if addr == "" {
|
||||
return true
|
||||
}
|
||||
return za.IPNet.Contains(net.ParseIP(addr))
|
||||
}
|
||||
// Set reference to the first config in the current block.
|
||||
// This is used later by MakeServers to share a single plugin list
|
||||
// for all zones in a server block.
|
||||
if ik == 0 {
|
||||
firstConfigInBlock = cfg
|
||||
}
|
||||
cfg.firstConfigInBlock = firstConfigInBlock
|
||||
|
||||
keyConfig := keyForConfig(ib, ik)
|
||||
h.saveConfig(keyConfig, cfg)
|
||||
}
|
||||
}
|
||||
@@ -107,6 +146,17 @@ func (h *dnsContext) MakeServers() ([]caddy.Server, error) {
|
||||
return nil, errValid
|
||||
}
|
||||
|
||||
// Copy the Plugin, ListenHosts and Debug from first config in the block
|
||||
// to all other config in the same block . Doing this results in zones
|
||||
// sharing the same plugin instances and settings as other zones in
|
||||
// the same block.
|
||||
for _, c := range h.configs {
|
||||
c.Plugin = c.firstConfigInBlock.Plugin
|
||||
c.ListenHosts = c.firstConfigInBlock.ListenHosts
|
||||
c.Debug = c.firstConfigInBlock.Debug
|
||||
c.TLSConfig = c.firstConfigInBlock.TLSConfig
|
||||
}
|
||||
|
||||
// we must map (group) each config to a bind address
|
||||
groups, err := groupConfigsByListenAddr(h.configs)
|
||||
if err != nil {
|
||||
@@ -223,7 +273,6 @@ func (h *dnsContext) validateZonesAndListeningAddresses() error {
|
||||
// address (what you pass into net.Listen) to the list of site configs.
|
||||
// This function does NOT vet the configs to ensure they are compatible.
|
||||
func groupConfigsByListenAddr(configs []*Config) (map[string][]*Config, error) {
|
||||
|
||||
groups := make(map[string][]*Config)
|
||||
for _, conf := range configs {
|
||||
for _, h := range conf.ListenHosts {
|
||||
|
51
vendor/github.com/coredns/coredns/core/dnsserver/server.go
generated
vendored
51
vendor/github.com/coredns/coredns/core/dnsserver/server.go
generated
vendored
@@ -10,6 +10,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/metrics/vars"
|
||||
"github.com/coredns/coredns/plugin/pkg/edns"
|
||||
@@ -20,7 +21,6 @@ import (
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
"github.com/coredns/coredns/request"
|
||||
|
||||
"github.com/caddyserver/caddy"
|
||||
"github.com/miekg/dns"
|
||||
ot "github.com/opentracing/opentracing-go"
|
||||
)
|
||||
@@ -66,10 +66,6 @@ func NewServer(addr string, group []*Config) (*Server, error) {
|
||||
if site.Debug {
|
||||
s.debug = true
|
||||
log.D.Set()
|
||||
} else {
|
||||
// When reloading we need to explicitly disable debug logging if it is now disabled.
|
||||
s.debug = false
|
||||
log.D.Clear()
|
||||
}
|
||||
// set the config per zone
|
||||
s.zones[site.Zone] = site
|
||||
@@ -97,6 +93,11 @@ func NewServer(addr string, group []*Config) (*Server, error) {
|
||||
site.pluginChain = stack
|
||||
}
|
||||
|
||||
if !s.debug {
|
||||
// When reloading we need to explicitly disable debug logging if it is now disabled.
|
||||
log.D.Clear()
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
@@ -109,6 +110,7 @@ func (s *Server) Serve(l net.Listener) error {
|
||||
s.m.Lock()
|
||||
s.server[tcp] = &dns.Server{Listener: l, Net: "tcp", Handler: dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
|
||||
ctx := context.WithValue(context.Background(), Key{}, s)
|
||||
ctx = context.WithValue(ctx, LoopKey{}, 0)
|
||||
s.ServeDNS(ctx, w, r)
|
||||
})}
|
||||
s.m.Unlock()
|
||||
@@ -122,6 +124,7 @@ func (s *Server) ServePacket(p net.PacketConn) error {
|
||||
s.m.Lock()
|
||||
s.server[udp] = &dns.Server{PacketConn: p, Net: "udp", Handler: dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
|
||||
ctx := context.WithValue(context.Background(), Key{}, s)
|
||||
ctx = context.WithValue(ctx, LoopKey{}, 0)
|
||||
s.ServeDNS(ctx, w, r)
|
||||
})}
|
||||
s.m.Unlock()
|
||||
@@ -193,7 +196,7 @@ func (s *Server) Stop() (err error) {
|
||||
// Address together with Stop() implement caddy.GracefulServer.
|
||||
func (s *Server) Address() string { return s.Addr }
|
||||
|
||||
// ServeDNS is the entry point for every request to the address that s
|
||||
// ServeDNS is the entry point for every request to the address that
|
||||
// is bound to. It acts as a multiplexer for the requests zonename as
|
||||
// defined in the request so that the correct zone
|
||||
// (configuration and plugin stack) will handle the request.
|
||||
@@ -210,7 +213,7 @@ func (s *Server) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
||||
// In case the user doesn't enable error plugin, we still
|
||||
// need to make sure that we stay alive up here
|
||||
if rec := recover(); rec != nil {
|
||||
log.Errorf("Recovered from panic in server: %q", s.Addr)
|
||||
log.Errorf("Recovered from panic in server: %q %v", s.Addr, rec)
|
||||
vars.Panic.Inc()
|
||||
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeServerFailure)
|
||||
}
|
||||
@@ -239,23 +242,16 @@ func (s *Server) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
||||
|
||||
for {
|
||||
if h, ok := s.zones[q[off:]]; ok {
|
||||
if h.pluginChain == nil { // zone defined, but has not got any plugins
|
||||
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeRefused)
|
||||
return
|
||||
}
|
||||
if r.Question[0].Qtype != dns.TypeDS {
|
||||
if h.FilterFunc == nil {
|
||||
rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
|
||||
if !plugin.ClientWrite(rcode) {
|
||||
errorFunc(s.Addr, w, r, rcode)
|
||||
}
|
||||
return
|
||||
}
|
||||
// FilterFunc is set, call it to see if we should use this handler.
|
||||
// This is given to full query name.
|
||||
if h.FilterFunc(q) {
|
||||
rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
|
||||
if !plugin.ClientWrite(rcode) {
|
||||
errorFunc(s.Addr, w, r, rcode)
|
||||
}
|
||||
return
|
||||
rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
|
||||
if !plugin.ClientWrite(rcode) {
|
||||
errorFunc(s.Addr, w, r, rcode)
|
||||
}
|
||||
return
|
||||
}
|
||||
// The type is DS, keep the handler, but keep on searching as maybe we are serving
|
||||
// the parent as well and the DS should be routed to it - this will probably *misroute* DS
|
||||
@@ -332,7 +328,7 @@ func errorAndMetricsFunc(server string, w dns.ResponseWriter, r *dns.Msg, rc int
|
||||
answer.SetRcode(r, rc)
|
||||
state.SizeAndDo(answer)
|
||||
|
||||
vars.Report(server, state, vars.Dropped, rcode.ToString(rc), answer.Len(), time.Now())
|
||||
vars.Report(server, state, vars.Dropped, rcode.ToString(rc), "" /* plugin */, answer.Len(), time.Now())
|
||||
|
||||
w.WriteMsg(answer)
|
||||
}
|
||||
@@ -342,8 +338,13 @@ const (
|
||||
udp = 1
|
||||
)
|
||||
|
||||
// Key is the context key for the current server added to the context.
|
||||
type Key struct{}
|
||||
type (
|
||||
// Key is the context key for the current server added to the context.
|
||||
Key struct{}
|
||||
|
||||
// LoopKey is the context key to detect server wide loops.
|
||||
LoopKey struct{}
|
||||
)
|
||||
|
||||
// EnableChaos is a map with plugin names for which we should open CH class queries as we block these by default.
|
||||
var EnableChaos = map[string]struct{}{
|
||||
|
10
vendor/github.com/coredns/coredns/core/dnsserver/server_grpc.go
generated
vendored
10
vendor/github.com/coredns/coredns/core/dnsserver/server_grpc.go
generated
vendored
@@ -7,11 +7,11 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/coredns/coredns/pb"
|
||||
"github.com/coredns/coredns/plugin/pkg/reuseport"
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
|
||||
"github.com/caddyserver/caddy"
|
||||
"github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
@@ -34,12 +34,17 @@ func NewServergRPC(addr string, group []*Config) (*ServergRPC, error) {
|
||||
return nil, err
|
||||
}
|
||||
// The *tls* plugin must make sure that multiple conflicting
|
||||
// TLS configuration return an error: it can only be specified once.
|
||||
// TLS configuration returns an error: it can only be specified once.
|
||||
var tlsConfig *tls.Config
|
||||
for _, conf := range s.zones {
|
||||
// Should we error if some configs *don't* have TLS?
|
||||
tlsConfig = conf.TLSConfig
|
||||
}
|
||||
// http/2 is required when using gRPC. We need to specify it in next protos
|
||||
// or the upgrade won't happen.
|
||||
if tlsConfig != nil {
|
||||
tlsConfig.NextProtos = []string{"h2"}
|
||||
}
|
||||
|
||||
return &ServergRPC{Server: s, tlsConfig: tlsConfig}, nil
|
||||
}
|
||||
@@ -134,6 +139,7 @@ func (s *ServergRPC) Query(ctx context.Context, in *pb.DnsPacket) (*pb.DnsPacket
|
||||
w := &gRPCresponse{localAddr: s.listenAddr, remoteAddr: a, Msg: msg}
|
||||
|
||||
dnsCtx := context.WithValue(ctx, Key{}, s.Server)
|
||||
dnsCtx = context.WithValue(dnsCtx, LoopKey{}, 0)
|
||||
s.ServeDNS(dnsCtx, w, msg)
|
||||
|
||||
packed, err := w.Msg.Pack()
|
||||
|
47
vendor/github.com/coredns/coredns/core/dnsserver/server_https.go
generated
vendored
47
vendor/github.com/coredns/coredns/core/dnsserver/server_https.go
generated
vendored
@@ -9,38 +9,60 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||
"github.com/coredns/coredns/plugin/pkg/doh"
|
||||
"github.com/coredns/coredns/plugin/pkg/response"
|
||||
"github.com/coredns/coredns/plugin/pkg/reuseport"
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
|
||||
"github.com/caddyserver/caddy"
|
||||
)
|
||||
|
||||
// ServerHTTPS represents an instance of a DNS-over-HTTPS server.
|
||||
type ServerHTTPS struct {
|
||||
*Server
|
||||
httpsServer *http.Server
|
||||
listenAddr net.Addr
|
||||
tlsConfig *tls.Config
|
||||
httpsServer *http.Server
|
||||
listenAddr net.Addr
|
||||
tlsConfig *tls.Config
|
||||
validRequest func(*http.Request) bool
|
||||
}
|
||||
|
||||
// NewServerHTTPS returns a new CoreDNS GRPC server and compiles all plugins in to it.
|
||||
// NewServerHTTPS returns a new CoreDNS HTTPS server and compiles all plugins in to it.
|
||||
func NewServerHTTPS(addr string, group []*Config) (*ServerHTTPS, error) {
|
||||
s, err := NewServer(addr, group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// The *tls* plugin must make sure that multiple conflicting
|
||||
// TLS configuration return an error: it can only be specified once.
|
||||
// TLS configuration returns an error: it can only be specified once.
|
||||
var tlsConfig *tls.Config
|
||||
for _, conf := range s.zones {
|
||||
// Should we error if some configs *don't* have TLS?
|
||||
tlsConfig = conf.TLSConfig
|
||||
}
|
||||
|
||||
sh := &ServerHTTPS{Server: s, tlsConfig: tlsConfig, httpsServer: new(http.Server)}
|
||||
// http/2 is recommended when using DoH. We need to specify it in next protos
|
||||
// or the upgrade won't happen.
|
||||
if tlsConfig != nil {
|
||||
tlsConfig.NextProtos = []string{"h2", "http/1.1"}
|
||||
}
|
||||
|
||||
// Use a custom request validation func or use the standard DoH path check.
|
||||
var validator func(*http.Request) bool
|
||||
for _, conf := range s.zones {
|
||||
validator = conf.HTTPRequestValidateFunc
|
||||
}
|
||||
if validator == nil {
|
||||
validator = func(r *http.Request) bool { return r.URL.Path == doh.Path }
|
||||
}
|
||||
|
||||
srv := &http.Server{
|
||||
ReadTimeout: 5 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
IdleTimeout: 120 * time.Second,
|
||||
}
|
||||
sh := &ServerHTTPS{
|
||||
Server: s, tlsConfig: tlsConfig, httpsServer: srv, validRequest: validator,
|
||||
}
|
||||
sh.httpsServer.Handler = sh
|
||||
|
||||
return sh, nil
|
||||
@@ -104,7 +126,7 @@ func (s *ServerHTTPS) Stop() error {
|
||||
// chain, converts it back and write it to the client.
|
||||
func (s *ServerHTTPS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if r.URL.Path != doh.Path {
|
||||
if !s.validRequest(r) {
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
@@ -118,11 +140,16 @@ func (s *ServerHTTPS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// Create a DoHWriter with the correct addresses in it.
|
||||
h, p, _ := net.SplitHostPort(r.RemoteAddr)
|
||||
port, _ := strconv.Atoi(p)
|
||||
dw := &DoHWriter{laddr: s.listenAddr, raddr: &net.TCPAddr{IP: net.ParseIP(h), Port: port}}
|
||||
dw := &DoHWriter{
|
||||
laddr: s.listenAddr,
|
||||
raddr: &net.TCPAddr{IP: net.ParseIP(h), Port: port},
|
||||
request: r,
|
||||
}
|
||||
|
||||
// We just call the normal chain handler - all error handling is done there.
|
||||
// We should expect a packet to be returned that we can send to the client.
|
||||
ctx := context.WithValue(context.Background(), Key{}, s.Server)
|
||||
ctx = context.WithValue(ctx, LoopKey{}, 0)
|
||||
s.ServeDNS(ctx, dw, msg)
|
||||
|
||||
// See section 4.2.1 of RFC 8484.
|
||||
|
5
vendor/github.com/coredns/coredns/core/dnsserver/server_tls.go
generated
vendored
5
vendor/github.com/coredns/coredns/core/dnsserver/server_tls.go
generated
vendored
@@ -6,10 +6,10 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/coredns/coredns/plugin/pkg/reuseport"
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
|
||||
"github.com/caddyserver/caddy"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@@ -26,7 +26,7 @@ func NewServerTLS(addr string, group []*Config) (*ServerTLS, error) {
|
||||
return nil, err
|
||||
}
|
||||
// The *tls* plugin must make sure that multiple conflicting
|
||||
// TLS configuration return an error: it can only be specified once.
|
||||
// TLS configuration returns an error: it can only be specified once.
|
||||
var tlsConfig *tls.Config
|
||||
for _, conf := range s.zones {
|
||||
// Should we error if some configs *don't* have TLS?
|
||||
@@ -50,6 +50,7 @@ func (s *ServerTLS) Serve(l net.Listener) error {
|
||||
// Only fill out the TCP server for this one.
|
||||
s.server[tcp] = &dns.Server{Listener: l, Net: "tcp-tls", Handler: dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
|
||||
ctx := context.WithValue(context.Background(), Key{}, s.Server)
|
||||
ctx = context.WithValue(ctx, LoopKey{}, 0)
|
||||
s.ServeDNS(ctx, w, r)
|
||||
})}
|
||||
s.m.Unlock()
|
||||
|
4
vendor/github.com/coredns/coredns/core/dnsserver/zdirectives.go
generated
vendored
4
vendor/github.com/coredns/coredns/core/dnsserver/zdirectives.go
generated
vendored
@@ -11,6 +11,7 @@ package dnsserver
|
||||
// care what plugin above them are doing.
|
||||
var Directives = []string{
|
||||
"metadata",
|
||||
"geoip",
|
||||
"cancel",
|
||||
"tls",
|
||||
"reload",
|
||||
@@ -27,6 +28,7 @@ var Directives = []string{
|
||||
"errors",
|
||||
"log",
|
||||
"dnstap",
|
||||
"local",
|
||||
"dns64",
|
||||
"acl",
|
||||
"any",
|
||||
@@ -34,8 +36,10 @@ var Directives = []string{
|
||||
"loadbalance",
|
||||
"cache",
|
||||
"rewrite",
|
||||
"header",
|
||||
"dnssec",
|
||||
"autopath",
|
||||
"minimal",
|
||||
"template",
|
||||
"transfer",
|
||||
"hosts",
|
||||
|
36
vendor/github.com/coredns/coredns/coremain/run.go
generated
vendored
36
vendor/github.com/coredns/coredns/coremain/run.go
generated
vendored
@@ -4,15 +4,13 @@ package coremain
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
|
||||
"github.com/caddyserver/caddy"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -36,21 +34,6 @@ func init() {
|
||||
// Run is CoreDNS's main() function.
|
||||
func Run() {
|
||||
caddy.TrapSignals()
|
||||
|
||||
// Reset flag.CommandLine to get rid of unwanted flags for instance from glog (used in kubernetes).
|
||||
// And read the ones we want to keep.
|
||||
flag.VisitAll(func(f *flag.Flag) {
|
||||
if _, ok := flagsBlacklist[f.Name]; ok {
|
||||
return
|
||||
}
|
||||
flagsToKeep = append(flagsToKeep, f)
|
||||
})
|
||||
|
||||
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
|
||||
for _, f := range flagsToKeep {
|
||||
flag.Var(f.Value, f.Name, f.Usage)
|
||||
}
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if len(flag.Args()) > 0 {
|
||||
@@ -112,7 +95,7 @@ func confLoader(serverType string) (caddy.Input, error) {
|
||||
return caddy.CaddyfileFromPipe(os.Stdin, serverType)
|
||||
}
|
||||
|
||||
contents, err := ioutil.ReadFile(conf)
|
||||
contents, err := os.ReadFile(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -125,7 +108,7 @@ func confLoader(serverType string) (caddy.Input, error) {
|
||||
|
||||
// defaultLoader loads the Corefile from the current working directory.
|
||||
func defaultLoader(serverType string) (caddy.Input, error) {
|
||||
contents, err := ioutil.ReadFile(caddy.DefaultConfigFile)
|
||||
contents, err := os.ReadFile(caddy.DefaultConfigFile)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
@@ -198,16 +181,3 @@ var (
|
||||
// Gitcommit contains the commit where we built CoreDNS from.
|
||||
GitCommit string
|
||||
)
|
||||
|
||||
// flagsBlacklist removes flags with these names from our flagset.
|
||||
var flagsBlacklist = map[string]struct{}{
|
||||
"logtostderr": {},
|
||||
"alsologtostderr": {},
|
||||
"v": {},
|
||||
"stderrthreshold": {},
|
||||
"vmodule": {},
|
||||
"log_backtrace_at": {},
|
||||
"log_dir": {},
|
||||
}
|
||||
|
||||
var flagsToKeep []*flag.Flag
|
||||
|
2
vendor/github.com/coredns/coredns/coremain/version.go
generated
vendored
2
vendor/github.com/coredns/coredns/coremain/version.go
generated
vendored
@@ -2,7 +2,7 @@ package coremain
|
||||
|
||||
// Various CoreDNS constants.
|
||||
const (
|
||||
CoreVersion = "1.7.0"
|
||||
CoreVersion = "1.8.7"
|
||||
coreName = "CoreDNS"
|
||||
serverType = "dns"
|
||||
)
|
||||
|
11
vendor/github.com/coredns/coredns/plugin/backend.go
generated
vendored
11
vendor/github.com/coredns/coredns/plugin/backend.go
generated
vendored
@@ -26,23 +26,14 @@ type ServiceBackend interface {
|
||||
// Note: it does not implement a specific service.
|
||||
Records(ctx context.Context, state request.Request, exact bool) ([]msg.Service, error)
|
||||
|
||||
// IsNameError return true if err indicated a record not found condition
|
||||
// IsNameError returns true if err indicated a record not found condition
|
||||
IsNameError(err error) bool
|
||||
|
||||
Transferer
|
||||
}
|
||||
|
||||
// Transferer defines an interface for backends that provide AXFR of all records.
|
||||
type Transferer interface {
|
||||
// Serial returns a SOA serial number to construct a SOA record.
|
||||
Serial(state request.Request) uint32
|
||||
|
||||
// MinTTL returns the minimum TTL to be used in the SOA record.
|
||||
MinTTL(state request.Request) uint32
|
||||
|
||||
// Transfer handles a zone transfer it writes to the client just
|
||||
// like any other handler.
|
||||
Transfer(ctx context.Context, state request.Request) (int, error)
|
||||
}
|
||||
|
||||
// Options are extra options that can be specified for a lookup.
|
||||
|
12
vendor/github.com/coredns/coredns/plugin/backend_lookup.go
generated
vendored
12
vendor/github.com/coredns/coredns/plugin/backend_lookup.go
generated
vendored
@@ -422,7 +422,7 @@ func NS(ctx context.Context, b ServiceBackend, zone string, state request.Reques
|
||||
old := state.QName()
|
||||
|
||||
state.Clear()
|
||||
state.Req.Question[0].Name = "ns.dns." + zone
|
||||
state.Req.Question[0].Name = dnsutil.Join("ns.dns.", zone)
|
||||
services, err := b.Services(ctx, state, false, opt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -440,8 +440,8 @@ func NS(ctx context.Context, b ServiceBackend, zone string, state request.Reques
|
||||
|
||||
case dns.TypeA, dns.TypeAAAA:
|
||||
serv.Host = msg.Domain(serv.Key)
|
||||
extra = append(extra, newAddress(serv, serv.Host, ip, what))
|
||||
ns := serv.NewNS(state.QName())
|
||||
extra = append(extra, newAddress(serv, ns.Ns, ip, what))
|
||||
if _, ok := seen[ns.Ns]; ok {
|
||||
continue
|
||||
}
|
||||
@@ -462,12 +462,8 @@ func SOA(ctx context.Context, b ServiceBackend, zone string, state request.Reque
|
||||
|
||||
header := dns.RR_Header{Name: zone, Rrtype: dns.TypeSOA, Ttl: ttl, Class: dns.ClassINET}
|
||||
|
||||
Mbox := hostmaster + "."
|
||||
Ns := "ns.dns."
|
||||
if zone[0] != '.' {
|
||||
Mbox += zone
|
||||
Ns += zone
|
||||
}
|
||||
Mbox := dnsutil.Join(hostmaster, zone)
|
||||
Ns := dnsutil.Join("ns.dns", zone)
|
||||
|
||||
soa := &dns.SOA{Hdr: header,
|
||||
Mbox: Mbox,
|
||||
|
8
vendor/github.com/coredns/coredns/plugin/cache/README.md
generated
vendored
8
vendor/github.com/coredns/coredns/plugin/cache/README.md
generated
vendored
@@ -10,6 +10,9 @@ With *cache* enabled, all records except zone transfers and metadata records wil
|
||||
3600s. Caching is mostly useful in a scenario when fetching data from the backend (upstream,
|
||||
database, etc.) is expensive.
|
||||
|
||||
*Cache* will change the query to enable DNSSEC (DNSSEC OK; DO) if it passes through the plugin. If
|
||||
the client didn't request any DNSSEC (records), these are filtered out when replying.
|
||||
|
||||
This plugin can only be used once per Server Block.
|
||||
|
||||
## Syntax
|
||||
@@ -72,9 +75,12 @@ If monitoring is enabled (via the *prometheus* plugin) then the following metric
|
||||
|
||||
* `coredns_cache_entries{server, type}` - Total elements in the cache by cache type.
|
||||
* `coredns_cache_hits_total{server, type}` - Counter of cache hits by cache type.
|
||||
* `coredns_cache_misses_total{server}` - Counter of cache misses.
|
||||
* `coredns_cache_misses_total{server}` - Counter of cache misses. - Deprecated, derive misses from cache hits/requests counters.
|
||||
* `coredns_cache_requests_total{server}` - Counter of cache requests.
|
||||
* `coredns_cache_prefetch_total{server}` - Counter of times the cache has prefetched a cached item.
|
||||
* `coredns_cache_drops_total{server}` - Counter of responses excluded from the cache due to request/response question name mismatch.
|
||||
* `coredns_cache_served_stale_total{server}` - Counter of requests served from stale cache entries.
|
||||
* `coredns_cache_evictions_total{server, type}` - Counter of cache evictions.
|
||||
|
||||
Cache types are either "denial" or "success". `Server` is the server handling the request, see the
|
||||
prometheus plugin for documentation.
|
||||
|
53
vendor/github.com/coredns/coredns/plugin/cache/cache.go
generated
vendored
53
vendor/github.com/coredns/coredns/plugin/cache/cache.go
generated
vendored
@@ -65,31 +65,21 @@ func New() *Cache {
|
||||
// key returns key under which we store the item, -1 will be returned if we don't store the message.
|
||||
// Currently we do not cache Truncated, errors zone transfers or dynamic update messages.
|
||||
// qname holds the already lowercased qname.
|
||||
func key(qname string, m *dns.Msg, t response.Type, do bool) (bool, uint64) {
|
||||
func key(qname string, m *dns.Msg, t response.Type) (bool, uint64) {
|
||||
// We don't store truncated responses.
|
||||
if m.Truncated {
|
||||
return false, 0
|
||||
}
|
||||
// Nor errors or Meta or Update
|
||||
// Nor errors or Meta or Update.
|
||||
if t == response.OtherError || t == response.Meta || t == response.Update {
|
||||
return false, 0
|
||||
}
|
||||
|
||||
return true, hash(qname, m.Question[0].Qtype, do)
|
||||
return true, hash(qname, m.Question[0].Qtype)
|
||||
}
|
||||
|
||||
var one = []byte("1")
|
||||
var zero = []byte("0")
|
||||
|
||||
func hash(qname string, qtype uint16, do bool) uint64 {
|
||||
func hash(qname string, qtype uint16) uint64 {
|
||||
h := fnv.New64()
|
||||
|
||||
if do {
|
||||
h.Write(one)
|
||||
} else {
|
||||
h.Write(zero)
|
||||
}
|
||||
|
||||
h.Write([]byte{byte(qtype >> 8)})
|
||||
h.Write([]byte{byte(qtype)})
|
||||
h.Write([]byte(qname))
|
||||
@@ -114,6 +104,7 @@ type ResponseWriter struct {
|
||||
state request.Request
|
||||
server string // Server handling the request.
|
||||
|
||||
do bool // When true the original request had the DO bit set.
|
||||
prefetch bool // When true write nothing back to the client.
|
||||
remoteAddr net.Addr
|
||||
}
|
||||
@@ -152,14 +143,10 @@ func (w *ResponseWriter) RemoteAddr() net.Addr {
|
||||
|
||||
// WriteMsg implements the dns.ResponseWriter interface.
|
||||
func (w *ResponseWriter) WriteMsg(res *dns.Msg) error {
|
||||
do := false
|
||||
mt, opt := response.Typify(res, w.now().UTC())
|
||||
if opt != nil {
|
||||
do = opt.Do()
|
||||
}
|
||||
mt, _ := response.Typify(res, w.now().UTC())
|
||||
|
||||
// key returns empty string for anything we don't want to cache.
|
||||
hasKey, key := key(w.state.Name(), res, mt, do)
|
||||
hasKey, key := key(w.state.Name(), res, mt)
|
||||
|
||||
msgTTL := dnsutil.MinimalTTL(res, mt)
|
||||
var duration time.Duration
|
||||
@@ -188,18 +175,16 @@ func (w *ResponseWriter) WriteMsg(res *dns.Msg) error {
|
||||
}
|
||||
|
||||
// Apply capped TTL to this reply to avoid jarring TTL experience 1799 -> 8 (e.g.)
|
||||
// We also may need to filter out DNSSEC records, see toMsg() for similar code.
|
||||
ttl := uint32(duration.Seconds())
|
||||
for i := range res.Answer {
|
||||
res.Answer[i].Header().Ttl = ttl
|
||||
}
|
||||
for i := range res.Ns {
|
||||
res.Ns[i].Header().Ttl = ttl
|
||||
}
|
||||
for i := range res.Extra {
|
||||
if res.Extra[i].Header().Rrtype != dns.TypeOPT {
|
||||
res.Extra[i].Header().Ttl = ttl
|
||||
}
|
||||
res.Answer = filterRRSlice(res.Answer, ttl, w.do, false)
|
||||
res.Ns = filterRRSlice(res.Ns, ttl, w.do, false)
|
||||
res.Extra = filterRRSlice(res.Extra, ttl, w.do, false)
|
||||
|
||||
if !w.do {
|
||||
res.AuthenticatedData = false // unset AD bit if client is not OK with DNSSEC
|
||||
}
|
||||
|
||||
return w.ResponseWriter.WriteMsg(res)
|
||||
}
|
||||
|
||||
@@ -209,7 +194,9 @@ func (w *ResponseWriter) set(m *dns.Msg, key uint64, mt response.Type, duration
|
||||
switch mt {
|
||||
case response.NoError, response.Delegation:
|
||||
i := newItem(m, w.now(), duration)
|
||||
w.pcache.Add(key, i)
|
||||
if w.pcache.Add(key, i) {
|
||||
evictions.WithLabelValues(w.server, Success).Inc()
|
||||
}
|
||||
// when pre-fetching, remove the negative cache entry if it exists
|
||||
if w.prefetch {
|
||||
w.ncache.Remove(key)
|
||||
@@ -217,7 +204,9 @@ func (w *ResponseWriter) set(m *dns.Msg, key uint64, mt response.Type, duration
|
||||
|
||||
case response.NameError, response.NoData, response.ServerError:
|
||||
i := newItem(m, w.now(), duration)
|
||||
w.ncache.Add(key, i)
|
||||
if w.ncache.Add(key, i) {
|
||||
evictions.WithLabelValues(w.server, Denial).Inc()
|
||||
}
|
||||
|
||||
case response.OtherError:
|
||||
// don't cache these
|
||||
|
46
vendor/github.com/coredns/coredns/plugin/cache/dnssec.go
generated
vendored
Normal file
46
vendor/github.com/coredns/coredns/plugin/cache/dnssec.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
package cache
|
||||
|
||||
import "github.com/miekg/dns"
|
||||
|
||||
// isDNSSEC returns true if r is a DNSSEC record. NSEC,NSEC3,DS and RRSIG/SIG
|
||||
// are DNSSEC records. DNSKEYs is not in this list on the assumption that the
|
||||
// client explicitly asked for it.
|
||||
func isDNSSEC(r dns.RR) bool {
|
||||
switch r.Header().Rrtype {
|
||||
case dns.TypeNSEC:
|
||||
return true
|
||||
case dns.TypeNSEC3:
|
||||
return true
|
||||
case dns.TypeDS:
|
||||
return true
|
||||
case dns.TypeRRSIG:
|
||||
return true
|
||||
case dns.TypeSIG:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// filterRRSlice filters rrs and removes DNSSEC RRs when do is false. In the returned slice
|
||||
// the TTLs are set to ttl. If dup is true the RRs in rrs are _copied_ into the slice that is
|
||||
// returned.
|
||||
func filterRRSlice(rrs []dns.RR, ttl uint32, do, dup bool) []dns.RR {
|
||||
j := 0
|
||||
rs := make([]dns.RR, len(rrs))
|
||||
for _, r := range rrs {
|
||||
if !do && isDNSSEC(r) {
|
||||
continue
|
||||
}
|
||||
if r.Header().Rrtype == dns.TypeOPT {
|
||||
continue
|
||||
}
|
||||
r.Header().Ttl = ttl
|
||||
if dup {
|
||||
rs[j] = dns.Copy(r)
|
||||
} else {
|
||||
rs[j] = r
|
||||
}
|
||||
j++
|
||||
}
|
||||
return rs[:j]
|
||||
}
|
75
vendor/github.com/coredns/coredns/plugin/cache/handler.go
generated
vendored
75
vendor/github.com/coredns/coredns/plugin/cache/handler.go
generated
vendored
@@ -14,50 +14,53 @@ import (
|
||||
|
||||
// ServeDNS implements the plugin.Handler interface.
|
||||
func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
state := request.Request{W: w, Req: r}
|
||||
rc := r.Copy() // We potentially modify r, to prevent other plugins from seeing this (r is a pointer), copy r into rc.
|
||||
state := request.Request{W: w, Req: rc}
|
||||
do := state.Do()
|
||||
|
||||
zone := plugin.Zones(c.Zones).Matches(state.Name())
|
||||
if zone == "" {
|
||||
return plugin.NextOrFailure(c.Name(), c.Next, ctx, w, r)
|
||||
return plugin.NextOrFailure(c.Name(), c.Next, ctx, w, rc)
|
||||
}
|
||||
|
||||
now := c.now().UTC()
|
||||
|
||||
server := metrics.WithServer(ctx)
|
||||
|
||||
// On cache miss, if the request has the OPT record and the DO bit set we leave the message as-is. If there isn't a DO bit
|
||||
// set we will modify the request to _add_ one. This means we will always do DNSSEC lookups on cache misses.
|
||||
// When writing to cache, any DNSSEC RRs in the response are written to cache with the response.
|
||||
// When sending a response to a non-DNSSEC client, we remove DNSSEC RRs from the response. We use a 2048 buffer size, which is
|
||||
// less than 4096 (and older default) and more than 1024 which may be too small. We might need to tweaks this
|
||||
// value to be smaller still to prevent UDP fragmentation?
|
||||
|
||||
ttl := 0
|
||||
i := c.getIgnoreTTL(now, state, server)
|
||||
if i != nil {
|
||||
ttl = i.ttl(now)
|
||||
}
|
||||
if i == nil {
|
||||
crr := &ResponseWriter{ResponseWriter: w, Cache: c, state: state, server: server}
|
||||
return plugin.NextOrFailure(c.Name(), c.Next, ctx, crr, r)
|
||||
crr := &ResponseWriter{ResponseWriter: w, Cache: c, state: state, server: server, do: do}
|
||||
return c.doRefresh(ctx, state, crr)
|
||||
}
|
||||
if ttl < 0 {
|
||||
servedStale.WithLabelValues(server).Inc()
|
||||
// Adjust the time to get a 0 TTL in the reply built from a stale item.
|
||||
now = now.Add(time.Duration(ttl) * time.Second)
|
||||
go func() {
|
||||
r := r.Copy()
|
||||
crr := &ResponseWriter{Cache: c, state: state, server: server, prefetch: true, remoteAddr: w.LocalAddr()}
|
||||
plugin.NextOrFailure(c.Name(), c.Next, ctx, crr, r)
|
||||
}()
|
||||
cw := newPrefetchResponseWriter(server, state, c)
|
||||
go c.doPrefetch(ctx, state, cw, i, now)
|
||||
} else if c.shouldPrefetch(i, now) {
|
||||
cw := newPrefetchResponseWriter(server, state, c)
|
||||
go c.doPrefetch(ctx, state, cw, i, now)
|
||||
}
|
||||
resp := i.toMsg(r, now)
|
||||
resp := i.toMsg(r, now, do)
|
||||
w.WriteMsg(resp)
|
||||
|
||||
if c.shouldPrefetch(i, now) {
|
||||
go c.doPrefetch(ctx, state, server, i, now)
|
||||
}
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
|
||||
func (c *Cache) doPrefetch(ctx context.Context, state request.Request, server string, i *item, now time.Time) {
|
||||
cw := newPrefetchResponseWriter(server, state, c)
|
||||
|
||||
cachePrefetches.WithLabelValues(server).Inc()
|
||||
plugin.NextOrFailure(c.Name(), c.Next, ctx, cw, state.Req)
|
||||
func (c *Cache) doPrefetch(ctx context.Context, state request.Request, cw *ResponseWriter, i *item, now time.Time) {
|
||||
cachePrefetches.WithLabelValues(cw.server).Inc()
|
||||
c.doRefresh(ctx, state, cw)
|
||||
|
||||
// When prefetching we loose the item i, and with it the frequency
|
||||
// that we've gathered sofar. See we copy the frequencies info back
|
||||
@@ -67,6 +70,13 @@ func (c *Cache) doPrefetch(ctx context.Context, state request.Request, server st
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cache) doRefresh(ctx context.Context, state request.Request, cw *ResponseWriter) (int, error) {
|
||||
if !state.Do() {
|
||||
setDo(state.Req)
|
||||
}
|
||||
return plugin.NextOrFailure(c.Name(), c.Next, ctx, cw, state.Req)
|
||||
}
|
||||
|
||||
func (c *Cache) shouldPrefetch(i *item, now time.Time) bool {
|
||||
if c.prefetch <= 0 {
|
||||
return false
|
||||
@@ -80,7 +90,8 @@ func (c *Cache) shouldPrefetch(i *item, now time.Time) bool {
|
||||
func (c *Cache) Name() string { return "cache" }
|
||||
|
||||
func (c *Cache) get(now time.Time, state request.Request, server string) (*item, bool) {
|
||||
k := hash(state.Name(), state.QType(), state.Do())
|
||||
k := hash(state.Name(), state.QType())
|
||||
cacheRequests.WithLabelValues(server).Inc()
|
||||
|
||||
if i, ok := c.ncache.Get(k); ok && i.(*item).ttl(now) > 0 {
|
||||
cacheHits.WithLabelValues(server, Denial).Inc()
|
||||
@@ -97,7 +108,8 @@ func (c *Cache) get(now time.Time, state request.Request, server string) (*item,
|
||||
|
||||
// getIgnoreTTL unconditionally returns an item if it exists in the cache.
|
||||
func (c *Cache) getIgnoreTTL(now time.Time, state request.Request, server string) *item {
|
||||
k := hash(state.Name(), state.QType(), state.Do())
|
||||
k := hash(state.Name(), state.QType())
|
||||
cacheRequests.WithLabelValues(server).Inc()
|
||||
|
||||
if i, ok := c.ncache.Get(k); ok {
|
||||
ttl := i.(*item).ttl(now)
|
||||
@@ -118,7 +130,7 @@ func (c *Cache) getIgnoreTTL(now time.Time, state request.Request, server string
|
||||
}
|
||||
|
||||
func (c *Cache) exists(state request.Request) *item {
|
||||
k := hash(state.Name(), state.QType(), state.Do())
|
||||
k := hash(state.Name(), state.QType())
|
||||
if i, ok := c.ncache.Get(k); ok {
|
||||
return i.(*item)
|
||||
}
|
||||
@@ -127,3 +139,22 @@ func (c *Cache) exists(state request.Request) *item {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setDo sets the DO bit and UDP buffer size in the message m.
|
||||
func setDo(m *dns.Msg) {
|
||||
o := m.IsEdns0()
|
||||
if o != nil {
|
||||
o.SetDo()
|
||||
o.SetUDPSize(defaultUDPBufSize)
|
||||
return
|
||||
}
|
||||
|
||||
o = &dns.OPT{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeOPT}}
|
||||
o.SetDo()
|
||||
o.SetUDPSize(defaultUDPBufSize)
|
||||
m.Extra = append(m.Extra, o)
|
||||
}
|
||||
|
||||
// defaultUDPBufsize is the bufsize the cache plugin uses on outgoing requests that don't
|
||||
// have an OPT RR.
|
||||
const defaultUDPBufSize = 2048
|
||||
|
23
vendor/github.com/coredns/coredns/plugin/cache/item.go
generated
vendored
23
vendor/github.com/coredns/coredns/plugin/cache/item.go
generated
vendored
@@ -4,6 +4,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/coredns/coredns/plugin/cache/freq"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@@ -55,7 +56,7 @@ func newItem(m *dns.Msg, now time.Time, d time.Duration) *item {
|
||||
// So we're forced to always set this to 1; regardless if the answer came from the cache or not.
|
||||
// On newer systems(e.g. ubuntu 16.04 with glib version 2.23), this issue is resolved.
|
||||
// So we may set this bit back to 0 in the future ?
|
||||
func (i *item) toMsg(m *dns.Msg, now time.Time) *dns.Msg {
|
||||
func (i *item) toMsg(m *dns.Msg, now time.Time, do bool) *dns.Msg {
|
||||
m1 := new(dns.Msg)
|
||||
m1.SetReply(m)
|
||||
|
||||
@@ -64,6 +65,9 @@ func (i *item) toMsg(m *dns.Msg, now time.Time) *dns.Msg {
|
||||
// just set it to true.
|
||||
m1.Authoritative = true
|
||||
m1.AuthenticatedData = i.AuthenticatedData
|
||||
if !do {
|
||||
m1.AuthenticatedData = false // when DNSSEC was not wanted, it can't be authenticated data.
|
||||
}
|
||||
m1.RecursionAvailable = i.RecursionAvailable
|
||||
m1.Rcode = i.Rcode
|
||||
|
||||
@@ -72,19 +76,10 @@ func (i *item) toMsg(m *dns.Msg, now time.Time) *dns.Msg {
|
||||
m1.Extra = make([]dns.RR, len(i.Extra))
|
||||
|
||||
ttl := uint32(i.ttl(now))
|
||||
for j, r := range i.Answer {
|
||||
m1.Answer[j] = dns.Copy(r)
|
||||
m1.Answer[j].Header().Ttl = ttl
|
||||
}
|
||||
for j, r := range i.Ns {
|
||||
m1.Ns[j] = dns.Copy(r)
|
||||
m1.Ns[j].Header().Ttl = ttl
|
||||
}
|
||||
// newItem skips OPT records, so we can just use i.Extra as is.
|
||||
for j, r := range i.Extra {
|
||||
m1.Extra[j] = dns.Copy(r)
|
||||
m1.Extra[j].Header().Ttl = ttl
|
||||
}
|
||||
m1.Answer = filterRRSlice(i.Answer, ttl, do, true)
|
||||
m1.Ns = filterRRSlice(i.Ns, ttl, do, true)
|
||||
m1.Extra = filterRRSlice(i.Extra, ttl, do, true)
|
||||
|
||||
return m1
|
||||
}
|
||||
|
||||
|
33
vendor/github.com/coredns/coredns/plugin/cache/metrics.go
generated
vendored
33
vendor/github.com/coredns/coredns/plugin/cache/metrics.go
generated
vendored
@@ -4,49 +4,64 @@ import (
|
||||
"github.com/coredns/coredns/plugin"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
var (
|
||||
// cacheSize is total elements in the cache by cache type.
|
||||
cacheSize = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||
cacheSize = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "cache",
|
||||
Name: "entries",
|
||||
Help: "The number of elements in the cache.",
|
||||
}, []string{"server", "type"})
|
||||
// cacheRequests is a counter of all requests through the cache.
|
||||
cacheRequests = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "cache",
|
||||
Name: "requests_total",
|
||||
Help: "The count of cache requests.",
|
||||
}, []string{"server"})
|
||||
// cacheHits is counter of cache hits by cache type.
|
||||
cacheHits = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
cacheHits = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "cache",
|
||||
Name: "hits_total",
|
||||
Help: "The count of cache hits.",
|
||||
}, []string{"server", "type"})
|
||||
// cacheMisses is the counter of cache misses.
|
||||
cacheMisses = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
// cacheMisses is the counter of cache misses. - Deprecated
|
||||
cacheMisses = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "cache",
|
||||
Name: "misses_total",
|
||||
Help: "The count of cache misses.",
|
||||
Help: "The count of cache misses. Deprecated, derive misses from cache hits/requests counters.",
|
||||
}, []string{"server"})
|
||||
// cachePrefetches is the number of time the cache has prefetched a cached item.
|
||||
cachePrefetches = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
cachePrefetches = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "cache",
|
||||
Name: "prefetch_total",
|
||||
Help: "The number of time the cache has prefetched a cached item.",
|
||||
Help: "The number of times the cache has prefetched a cached item.",
|
||||
}, []string{"server"})
|
||||
// cacheDrops is the number responses that are not cached, because the reply is malformed.
|
||||
cacheDrops = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
cacheDrops = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "cache",
|
||||
Name: "drops_total",
|
||||
Help: "The number responses that are not cached, because the reply is malformed.",
|
||||
}, []string{"server"})
|
||||
// servedStale is the number of requests served from stale cache entries.
|
||||
servedStale = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
servedStale = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "cache",
|
||||
Name: "served_stale_total",
|
||||
Help: "The number of requests served from stale cache entries.",
|
||||
}, []string{"server"})
|
||||
// evictions is the counter of cache evictions.
|
||||
evictions = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "cache",
|
||||
Name: "evictions_total",
|
||||
Help: "The count of cache evictions.",
|
||||
}, []string{"server", "type"})
|
||||
)
|
||||
|
22
vendor/github.com/coredns/coredns/plugin/cache/setup.go
generated
vendored
22
vendor/github.com/coredns/coredns/plugin/cache/setup.go
generated
vendored
@@ -6,13 +6,11 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/metrics"
|
||||
"github.com/coredns/coredns/plugin/pkg/cache"
|
||||
clog "github.com/coredns/coredns/plugin/pkg/log"
|
||||
|
||||
"github.com/caddyserver/caddy"
|
||||
)
|
||||
|
||||
var log = clog.NewWithPlugin("cache")
|
||||
@@ -29,13 +27,6 @@ func setup(c *caddy.Controller) error {
|
||||
return ca
|
||||
})
|
||||
|
||||
c.OnStartup(func() error {
|
||||
metrics.MustRegister(c,
|
||||
cacheSize, cacheHits, cacheMisses,
|
||||
cachePrefetches, cacheDrops, servedStale)
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -50,10 +41,7 @@ func cacheParse(c *caddy.Controller) (*Cache, error) {
|
||||
j++
|
||||
|
||||
// cache [ttl] [zones..]
|
||||
origins := make([]string, len(c.ServerBlockKeys))
|
||||
copy(origins, c.ServerBlockKeys)
|
||||
args := c.RemainingArgs()
|
||||
|
||||
if len(args) > 0 {
|
||||
// first args may be just a number, then it is the ttl, if not it is a zone
|
||||
ttl, err := strconv.Atoi(args[0])
|
||||
@@ -66,10 +54,8 @@ func cacheParse(c *caddy.Controller) (*Cache, error) {
|
||||
ca.nttl = time.Duration(ttl) * time.Second
|
||||
args = args[1:]
|
||||
}
|
||||
if len(args) > 0 {
|
||||
copy(origins, args)
|
||||
}
|
||||
}
|
||||
origins := plugin.OriginsFromArgsOrServerBlock(args, c.ServerBlockKeys)
|
||||
|
||||
// Refinements? In an extra block.
|
||||
for c.NextBlock() {
|
||||
@@ -198,11 +184,7 @@ func cacheParse(c *caddy.Controller) (*Cache, error) {
|
||||
}
|
||||
}
|
||||
|
||||
for i := range origins {
|
||||
origins[i] = plugin.Host(origins[i]).Normalize()
|
||||
}
|
||||
ca.Zones = origins
|
||||
|
||||
ca.pcache = cache.New(ca.pcap)
|
||||
ca.ncache = cache.New(ca.ncap)
|
||||
}
|
||||
|
6
vendor/github.com/coredns/coredns/plugin/metrics/README.md
generated
vendored
6
vendor/github.com/coredns/coredns/plugin/metrics/README.md
generated
vendored
@@ -17,7 +17,7 @@ The following metrics are exported:
|
||||
* `coredns_dns_request_size_bytes{server, zone, proto}` - size of the request in bytes.
|
||||
* `coredns_dns_do_requests_total{server, zone}` - queries that have the DO bit set
|
||||
* `coredns_dns_response_size_bytes{server, zone, proto}` - response size in bytes.
|
||||
* `coredns_dns_responses_total{server, zone, rcode}` - response per zone and rcode.
|
||||
* `coredns_dns_responses_total{server, zone, rcode, plugin}` - response per zone, rcode and plugin.
|
||||
* `coredns_plugin_enabled{server, zone, name}` - indicates whether a plugin is enabled on per server and zone basis.
|
||||
|
||||
Each counter has a label `zone` which is the zonename used for the request/response.
|
||||
@@ -30,8 +30,10 @@ Extra labels used are:
|
||||
* `proto` which holds the transport of the response ("udp" or "tcp")
|
||||
* The address family (`family`) of the transport (1 = IP (IP version 4), 2 = IP6 (IP version 6)).
|
||||
* `type` which holds the query type. It holds most common types (A, AAAA, MX, SOA, CNAME, PTR, TXT,
|
||||
NS, SRV, DS, DNSKEY, RRSIG, NSEC, NSEC3, IXFR, AXFR and ANY) and "other" which lumps together all
|
||||
NS, SRV, DS, DNSKEY, RRSIG, NSEC, NSEC3, HTTPS, IXFR, AXFR and ANY) and "other" which lumps together all
|
||||
other types.
|
||||
* the `plugin` label holds the name of the plugin that made the write to the client. If the server
|
||||
did the write (on error for instance), the value is empty.
|
||||
|
||||
If monitoring is enabled, queries that do not enter the plugin chain are exported under the fake
|
||||
name "dropped" (without a closing dot - this is never a valid domain name).
|
||||
|
28
vendor/github.com/coredns/coredns/plugin/metrics/handler.go
generated
vendored
28
vendor/github.com/coredns/coredns/plugin/metrics/handler.go
generated
vendored
@@ -2,10 +2,10 @@ package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/metrics/vars"
|
||||
"github.com/coredns/coredns/plugin/pkg/dnstest"
|
||||
"github.com/coredns/coredns/plugin/pkg/rcode"
|
||||
"github.com/coredns/coredns/request"
|
||||
|
||||
@@ -23,13 +23,35 @@ func (m *Metrics) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg
|
||||
}
|
||||
|
||||
// Record response to get status code and size of the reply.
|
||||
rw := dnstest.NewRecorder(w)
|
||||
rw := NewRecorder(w)
|
||||
status, err := plugin.NextOrFailure(m.Name(), m.Next, ctx, rw, r)
|
||||
|
||||
vars.Report(WithServer(ctx), state, zone, rcode.ToString(rw.Rcode), rw.Len, rw.Start)
|
||||
rc := rw.Rcode
|
||||
if !plugin.ClientWrite(status) {
|
||||
// when no response was written, fallback to status returned from next plugin as this status
|
||||
// is actually used as rcode of DNS response
|
||||
// see https://github.com/coredns/coredns/blob/master/core/dnsserver/server.go#L318
|
||||
rc = status
|
||||
}
|
||||
plugin := m.authoritativePlugin(rw.Caller)
|
||||
vars.Report(WithServer(ctx), state, zone, rcode.ToString(rc), plugin, rw.Len, rw.Start)
|
||||
|
||||
return status, err
|
||||
}
|
||||
|
||||
// Name implements the Handler interface.
|
||||
func (m *Metrics) Name() string { return "prometheus" }
|
||||
|
||||
// authoritativePlugin returns which of made the write, if none is found the empty string is returned.
|
||||
func (m *Metrics) authoritativePlugin(caller [3]string) string {
|
||||
// a b and c contain the full path of the caller, the plugin name 2nd last elements
|
||||
// .../coredns/plugin/whoami/whoami.go --> whoami
|
||||
// this is likely FS specific, so use filepath.
|
||||
for _, c := range caller {
|
||||
plug := filepath.Base(filepath.Dir(c))
|
||||
if _, ok := m.plugins[plug]; ok {
|
||||
return plug
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
37
vendor/github.com/coredns/coredns/plugin/metrics/metrics.go
generated
vendored
37
vendor/github.com/coredns/coredns/plugin/metrics/metrics.go
generated
vendored
@@ -8,11 +8,12 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/metrics/vars"
|
||||
"github.com/coredns/coredns/plugin/pkg/reuseport"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
@@ -31,29 +32,18 @@ type Metrics struct {
|
||||
zoneNames []string
|
||||
zoneMap map[string]struct{}
|
||||
zoneMu sync.RWMutex
|
||||
|
||||
plugins map[string]struct{} // all available plugins, used to determine which plugin made the client write
|
||||
}
|
||||
|
||||
// New returns a new instance of Metrics with the given address.
|
||||
func New(addr string) *Metrics {
|
||||
met := &Metrics{
|
||||
Addr: addr,
|
||||
Reg: prometheus.NewRegistry(),
|
||||
Reg: prometheus.DefaultRegisterer.(*prometheus.Registry),
|
||||
zoneMap: make(map[string]struct{}),
|
||||
plugins: pluginList(caddy.ListPlugins()),
|
||||
}
|
||||
// Add the default collectors
|
||||
met.MustRegister(prometheus.NewGoCollector())
|
||||
met.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
|
||||
|
||||
// Add all of our collectors
|
||||
met.MustRegister(buildInfo)
|
||||
met.MustRegister(vars.Panic)
|
||||
met.MustRegister(vars.RequestCount)
|
||||
met.MustRegister(vars.RequestDuration)
|
||||
met.MustRegister(vars.RequestSize)
|
||||
met.MustRegister(vars.RequestDo)
|
||||
met.MustRegister(vars.ResponseSize)
|
||||
met.MustRegister(vars.ResponseRcode)
|
||||
met.MustRegister(vars.PluginEnabled)
|
||||
|
||||
return met
|
||||
}
|
||||
@@ -154,6 +144,19 @@ func keys(m map[string]struct{}) []string {
|
||||
return sx
|
||||
}
|
||||
|
||||
// pluginList iterates over the returned plugin map from caddy and removes the "dns." prefix from them.
|
||||
func pluginList(m map[string][]string) map[string]struct{} {
|
||||
pm := map[string]struct{}{}
|
||||
for _, p := range m["others"] {
|
||||
// only add 'dns.' plugins
|
||||
if len(p) > 3 {
|
||||
pm[p[4:]] = struct{}{}
|
||||
continue
|
||||
}
|
||||
}
|
||||
return pm
|
||||
}
|
||||
|
||||
// ListenAddr is assigned the address of the prometheus listener. Its use is mainly in tests where
|
||||
// we listen on "localhost:0" and need to retrieve the actual address.
|
||||
var ListenAddr string
|
||||
@@ -162,7 +165,7 @@ var ListenAddr string
|
||||
// before erroring when it tries to close the metrics server
|
||||
const shutdownTimeout time.Duration = time.Second * 5
|
||||
|
||||
var buildInfo = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||
var buildInfo = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Name: "build_info",
|
||||
Help: "A metric with a constant '1' value labeled by version, revision, and goversion from which CoreDNS was built.",
|
||||
|
30
vendor/github.com/coredns/coredns/plugin/metrics/recorder.go
generated
vendored
Normal file
30
vendor/github.com/coredns/coredns/plugin/metrics/recorder.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/dnstest"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Recorder is a dnstest.Recorder specific to the metrics plugin.
|
||||
type Recorder struct {
|
||||
*dnstest.Recorder
|
||||
// CallerN holds the string return value of the call to runtime.Caller(N+1)
|
||||
Caller [3]string
|
||||
}
|
||||
|
||||
// NewRecorder makes and returns a new Recorder.
|
||||
func NewRecorder(w dns.ResponseWriter) *Recorder { return &Recorder{Recorder: dnstest.NewRecorder(w)} }
|
||||
|
||||
// WriteMsg records the status code and calls the
|
||||
// underlying ResponseWriter's WriteMsg method.
|
||||
func (r *Recorder) WriteMsg(res *dns.Msg) error {
|
||||
_, r.Caller[0], _, _ = runtime.Caller(1)
|
||||
_, r.Caller[1], _, _ = runtime.Caller(2)
|
||||
_, r.Caller[2], _, _ = runtime.Caller(3)
|
||||
r.Len += res.Len()
|
||||
r.Msg = res
|
||||
return r.ResponseWriter.WriteMsg(res)
|
||||
}
|
23
vendor/github.com/coredns/coredns/plugin/metrics/register.go
generated
vendored
23
vendor/github.com/coredns/coredns/plugin/metrics/register.go
generated
vendored
@@ -1,23 +0,0 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
|
||||
"github.com/caddyserver/caddy"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// MustRegister registers the prometheus Collectors when the metrics plugin is used.
|
||||
func MustRegister(c *caddy.Controller, cs ...prometheus.Collector) {
|
||||
m := dnsserver.GetConfig(c).Handler("prometheus")
|
||||
if m == nil {
|
||||
return
|
||||
}
|
||||
x, ok := m.(*Metrics)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
for _, c := range cs {
|
||||
x.MustRegister(c)
|
||||
}
|
||||
}
|
8
vendor/github.com/coredns/coredns/plugin/metrics/setup.go
generated
vendored
8
vendor/github.com/coredns/coredns/plugin/metrics/setup.go
generated
vendored
@@ -4,14 +4,13 @@ import (
|
||||
"net"
|
||||
"runtime"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
"github.com/coredns/coredns/coremain"
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/metrics/vars"
|
||||
clog "github.com/coredns/coredns/plugin/pkg/log"
|
||||
"github.com/coredns/coredns/plugin/pkg/uniq"
|
||||
|
||||
"github.com/caddyserver/caddy"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -81,8 +80,9 @@ func parse(c *caddy.Controller) (*Metrics, error) {
|
||||
}
|
||||
i++
|
||||
|
||||
for _, z := range c.ServerBlockKeys {
|
||||
met.AddZone(plugin.Host(z).Normalize())
|
||||
zones := plugin.OriginsFromArgsOrServerBlock(nil /* args */, c.ServerBlockKeys)
|
||||
for _, z := range zones {
|
||||
met.AddZone(z)
|
||||
}
|
||||
args := c.RemainingArgs()
|
||||
|
||||
|
36
vendor/github.com/coredns/coredns/plugin/metrics/vars/monitor.go
generated
vendored
Normal file
36
vendor/github.com/coredns/coredns/plugin/metrics/vars/monitor.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package vars
|
||||
|
||||
import (
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
var monitorType = map[uint16]struct{}{
|
||||
dns.TypeAAAA: {},
|
||||
dns.TypeA: {},
|
||||
dns.TypeCNAME: {},
|
||||
dns.TypeDNSKEY: {},
|
||||
dns.TypeDS: {},
|
||||
dns.TypeMX: {},
|
||||
dns.TypeNSEC3: {},
|
||||
dns.TypeNSEC: {},
|
||||
dns.TypeNS: {},
|
||||
dns.TypePTR: {},
|
||||
dns.TypeRRSIG: {},
|
||||
dns.TypeSOA: {},
|
||||
dns.TypeSRV: {},
|
||||
dns.TypeTXT: {},
|
||||
dns.TypeHTTPS: {},
|
||||
// Meta Qtypes
|
||||
dns.TypeIXFR: {},
|
||||
dns.TypeAXFR: {},
|
||||
dns.TypeANY: {},
|
||||
}
|
||||
|
||||
// qTypeString returns the RR type based on monitorType. It returns the text representation
|
||||
// of those types. RR types not in that list will have "other" returned.
|
||||
func qTypeString(qtype uint16) string {
|
||||
if _, known := monitorType[qtype]; known {
|
||||
return dns.Type(qtype).String()
|
||||
}
|
||||
return "other"
|
||||
}
|
42
vendor/github.com/coredns/coredns/plugin/metrics/vars/report.go
generated
vendored
42
vendor/github.com/coredns/coredns/plugin/metrics/vars/report.go
generated
vendored
@@ -4,14 +4,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/coredns/coredns/request"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Report reports the metrics data associated with request. This function is exported because it is also
|
||||
// called from core/dnsserver to report requests hitting the server that should not be handled and are thus
|
||||
// not sent down the plugin chain.
|
||||
func Report(server string, req request.Request, zone, rcode string, size int, start time.Time) {
|
||||
func Report(server string, req request.Request, zone, rcode, plugin string, size int, start time.Time) {
|
||||
// Proto and Family.
|
||||
net := req.Proto()
|
||||
fam := "1"
|
||||
@@ -19,45 +17,17 @@ func Report(server string, req request.Request, zone, rcode string, size int, st
|
||||
fam = "2"
|
||||
}
|
||||
|
||||
typ := req.QType()
|
||||
|
||||
if req.Do() {
|
||||
RequestDo.WithLabelValues(server, zone).Inc()
|
||||
}
|
||||
|
||||
if _, known := monitorType[typ]; known {
|
||||
RequestCount.WithLabelValues(server, zone, net, fam, dns.Type(typ).String()).Inc()
|
||||
RequestDuration.WithLabelValues(server, zone, dns.Type(typ).String()).Observe(time.Since(start).Seconds())
|
||||
} else {
|
||||
RequestCount.WithLabelValues(server, zone, net, fam, other).Inc()
|
||||
RequestDuration.WithLabelValues(server, zone, other).Observe(time.Since(start).Seconds())
|
||||
}
|
||||
qType := qTypeString(req.QType())
|
||||
RequestCount.WithLabelValues(server, zone, net, fam, qType).Inc()
|
||||
|
||||
RequestDuration.WithLabelValues(server, zone).Observe(time.Since(start).Seconds())
|
||||
|
||||
ResponseSize.WithLabelValues(server, zone, net).Observe(float64(size))
|
||||
RequestSize.WithLabelValues(server, zone, net).Observe(float64(req.Len()))
|
||||
|
||||
ResponseRcode.WithLabelValues(server, zone, rcode).Inc()
|
||||
ResponseRcode.WithLabelValues(server, zone, rcode, plugin).Inc()
|
||||
}
|
||||
|
||||
var monitorType = map[uint16]struct{}{
|
||||
dns.TypeAAAA: {},
|
||||
dns.TypeA: {},
|
||||
dns.TypeCNAME: {},
|
||||
dns.TypeDNSKEY: {},
|
||||
dns.TypeDS: {},
|
||||
dns.TypeMX: {},
|
||||
dns.TypeNSEC3: {},
|
||||
dns.TypeNSEC: {},
|
||||
dns.TypeNS: {},
|
||||
dns.TypePTR: {},
|
||||
dns.TypeRRSIG: {},
|
||||
dns.TypeSOA: {},
|
||||
dns.TypeSRV: {},
|
||||
dns.TypeTXT: {},
|
||||
// Meta Qtypes
|
||||
dns.TypeIXFR: {},
|
||||
dns.TypeAXFR: {},
|
||||
dns.TypeANY: {},
|
||||
}
|
||||
|
||||
const other = "other"
|
||||
|
25
vendor/github.com/coredns/coredns/plugin/metrics/vars/vars.go
generated
vendored
25
vendor/github.com/coredns/coredns/plugin/metrics/vars/vars.go
generated
vendored
@@ -4,41 +4,42 @@ import (
|
||||
"github.com/coredns/coredns/plugin"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
// Request* and Response* are the prometheus counters and gauges we are using for exporting metrics.
|
||||
var (
|
||||
RequestCount = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
RequestCount = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "requests_total",
|
||||
Help: "Counter of DNS requests made per zone, protocol and family.",
|
||||
}, []string{"server", "zone", "proto", "family", "type"})
|
||||
|
||||
RequestDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
RequestDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "request_duration_seconds",
|
||||
Buckets: plugin.TimeBuckets,
|
||||
Help: "Histogram of the time (in seconds) each request took.",
|
||||
}, []string{"server", "zone", "type"})
|
||||
Help: "Histogram of the time (in seconds) each request took per zone.",
|
||||
}, []string{"server", "zone"})
|
||||
|
||||
RequestSize = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
RequestSize = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "request_size_bytes",
|
||||
Help: "Size of the EDNS0 UDP buffer in bytes (64K for TCP).",
|
||||
Help: "Size of the EDNS0 UDP buffer in bytes (64K for TCP) per zone and protocol.",
|
||||
Buckets: []float64{0, 100, 200, 300, 400, 511, 1023, 2047, 4095, 8291, 16e3, 32e3, 48e3, 64e3},
|
||||
}, []string{"server", "zone", "proto"})
|
||||
|
||||
RequestDo = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
RequestDo = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "do_requests_total",
|
||||
Help: "Counter of DNS requests with DO bit set per zone.",
|
||||
}, []string{"server", "zone"})
|
||||
|
||||
ResponseSize = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
ResponseSize = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "response_size_bytes",
|
||||
@@ -46,20 +47,20 @@ var (
|
||||
Buckets: []float64{0, 100, 200, 300, 400, 511, 1023, 2047, 4095, 8291, 16e3, 32e3, 48e3, 64e3},
|
||||
}, []string{"server", "zone", "proto"})
|
||||
|
||||
ResponseRcode = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
ResponseRcode = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "responses_total",
|
||||
Help: "Counter of response status codes.",
|
||||
}, []string{"server", "zone", "rcode"})
|
||||
}, []string{"server", "zone", "rcode", "plugin"})
|
||||
|
||||
Panic = prometheus.NewCounter(prometheus.CounterOpts{
|
||||
Panic = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Name: "panics_total",
|
||||
Help: "A metrics that counts the number of panics.",
|
||||
})
|
||||
|
||||
PluginEnabled = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||
PluginEnabled = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Name: "plugin_enabled",
|
||||
Help: "A metric that indicates whether a plugin is enabled on per server and zone basis.",
|
||||
|
139
vendor/github.com/coredns/coredns/plugin/normalize.go
generated
vendored
139
vendor/github.com/coredns/coredns/plugin/normalize.go
generated
vendored
@@ -3,10 +3,14 @@ package plugin
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/cidr"
|
||||
"github.com/coredns/coredns/plugin/pkg/log"
|
||||
"github.com/coredns/coredns/plugin/pkg/parse"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@@ -62,81 +66,132 @@ type (
|
||||
// Normalize will return the host portion of host, stripping
|
||||
// of any port or transport. The host will also be fully qualified and lowercased.
|
||||
// An empty string is returned on failure
|
||||
// Deprecated: use OriginsFromArgsOrServerBlock or NormalizeExact
|
||||
func (h Host) Normalize() string {
|
||||
// The error can be ignored here, because this function should only be called after the corefile has already been vetted.
|
||||
host, _ := h.MustNormalize()
|
||||
return host
|
||||
var caller string
|
||||
if _, file, line, ok := runtime.Caller(1); ok {
|
||||
caller = fmt.Sprintf("(%v line %d) ", file, line)
|
||||
}
|
||||
log.Warning("An external plugin " + caller + "is using the deprecated function Normalize. " +
|
||||
"This will be removed in a future versions of CoreDNS. The plugin should be updated to use " +
|
||||
"OriginsFromArgsOrServerBlock or NormalizeExact instead.")
|
||||
|
||||
s := string(h)
|
||||
_, s = parse.Transport(s)
|
||||
|
||||
// The error can be ignored here, because this function is called after the corefile has already been vetted.
|
||||
hosts, _, err := SplitHostPort(s)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return Name(hosts[0]).Normalize()
|
||||
}
|
||||
|
||||
// MustNormalize will return the host portion of host, stripping
|
||||
// of any port or transport. The host will also be fully qualified and lowercased.
|
||||
// An error is returned on error
|
||||
// Deprecated: use OriginsFromArgsOrServerBlock or NormalizeExact
|
||||
func (h Host) MustNormalize() (string, error) {
|
||||
var caller string
|
||||
if _, file, line, ok := runtime.Caller(1); ok {
|
||||
caller = fmt.Sprintf("(%v line %d) ", file, line)
|
||||
}
|
||||
log.Warning("An external plugin " + caller + "is using the deprecated function MustNormalize. " +
|
||||
"This will be removed in a future versions of CoreDNS. The plugin should be updated to use " +
|
||||
"OriginsFromArgsOrServerBlock or NormalizeExact instead.")
|
||||
|
||||
s := string(h)
|
||||
_, s = parse.Transport(s)
|
||||
|
||||
// The error can be ignored here, because this function is called after the corefile has already been vetted.
|
||||
host, _, _, err := SplitHostPort(s)
|
||||
hosts, _, err := SplitHostPort(s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return Name(host).Normalize(), nil
|
||||
return Name(hosts[0]).Normalize(), nil
|
||||
}
|
||||
|
||||
// SplitHostPort splits s up in a host and port portion, taking reverse address notation into account.
|
||||
// String the string s should *not* be prefixed with any protocols, i.e. dns://. The returned ipnet is the
|
||||
// *net.IPNet that is used when the zone is a reverse and a netmask is given.
|
||||
func SplitHostPort(s string) (host, port string, ipnet *net.IPNet, err error) {
|
||||
// NormalizeExact will return the host portion of host, stripping
|
||||
// of any port or transport. The host will also be fully qualified and lowercased.
|
||||
// An empty slice is returned on failure
|
||||
func (h Host) NormalizeExact() []string {
|
||||
// The error can be ignored here, because this function should only be called after the corefile has already been vetted.
|
||||
s := string(h)
|
||||
_, s = parse.Transport(s)
|
||||
|
||||
hosts, _, err := SplitHostPort(s)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for i := range hosts {
|
||||
hosts[i] = Name(hosts[i]).Normalize()
|
||||
|
||||
}
|
||||
return hosts
|
||||
}
|
||||
|
||||
// SplitHostPort splits s up in a host(s) and port portion, taking reverse address notation into account.
|
||||
// String the string s should *not* be prefixed with any protocols, i.e. dns://. SplitHostPort can return
|
||||
// multiple hosts when a reverse notation on a non-octet boundary is given.
|
||||
func SplitHostPort(s string) (hosts []string, port string, err error) {
|
||||
// If there is: :[0-9]+ on the end we assume this is the port. This works for (ascii) domain
|
||||
// names and our reverse syntax, which always needs a /mask *before* the port.
|
||||
// So from the back, find first colon, and then check if it's a number.
|
||||
host = s
|
||||
|
||||
colon := strings.LastIndex(s, ":")
|
||||
if colon == len(s)-1 {
|
||||
return "", "", nil, fmt.Errorf("expecting data after last colon: %q", s)
|
||||
return nil, "", fmt.Errorf("expecting data after last colon: %q", s)
|
||||
}
|
||||
if colon != -1 {
|
||||
if p, err := strconv.Atoi(s[colon+1:]); err == nil {
|
||||
port = strconv.Itoa(p)
|
||||
host = s[:colon]
|
||||
s = s[:colon]
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(miek): this should take escaping into account.
|
||||
if len(host) > 255 {
|
||||
return "", "", nil, fmt.Errorf("specified zone is too long: %d > 255", len(host))
|
||||
if len(s) > 255 {
|
||||
return nil, "", fmt.Errorf("specified zone is too long: %d > 255", len(s))
|
||||
}
|
||||
|
||||
_, d := dns.IsDomainName(host)
|
||||
if !d {
|
||||
return "", "", nil, fmt.Errorf("zone is not a valid domain name: %s", host)
|
||||
if _, ok := dns.IsDomainName(s); !ok {
|
||||
return nil, "", fmt.Errorf("zone is not a valid domain name: %s", s)
|
||||
}
|
||||
|
||||
// Check if it parses as a reverse zone, if so we use that. Must be fully specified IP and mask.
|
||||
ip, n, err := net.ParseCIDR(host)
|
||||
ones, bits := 0, 0
|
||||
if err == nil {
|
||||
if rev, e := dns.ReverseAddr(ip.String()); e == nil {
|
||||
ones, bits = n.Mask.Size()
|
||||
// get the size, in bits, of each portion of hostname defined in the reverse address. (8 for IPv4, 4 for IPv6)
|
||||
sizeDigit := 8
|
||||
if len(n.IP) == net.IPv6len {
|
||||
sizeDigit = 4
|
||||
}
|
||||
// Get the first lower octet boundary to see what encompassing zone we should be authoritative for.
|
||||
mod := (bits - ones) % sizeDigit
|
||||
nearest := (bits - ones) + mod
|
||||
offset := 0
|
||||
var end bool
|
||||
for i := 0; i < nearest/sizeDigit; i++ {
|
||||
offset, end = dns.NextLabel(rev, offset)
|
||||
if end {
|
||||
break
|
||||
}
|
||||
}
|
||||
host = rev[offset:]
|
||||
}
|
||||
_, n, err := net.ParseCIDR(s)
|
||||
if err != nil {
|
||||
return []string{s}, port, nil
|
||||
}
|
||||
return host, port, n, nil
|
||||
|
||||
if s[0] == ':' || (s[0] == '0' && strings.Contains(s, ":")) {
|
||||
return nil, "", fmt.Errorf("invalid CIDR %s", s)
|
||||
}
|
||||
|
||||
// now check if multiple hosts must be returned.
|
||||
nets := cidr.Split(n)
|
||||
hosts = cidr.Reverse(nets)
|
||||
return hosts, port, nil
|
||||
}
|
||||
|
||||
// OriginsFromArgsOrServerBlock returns the normalized args if that slice
|
||||
// is not empty, otherwise the serverblock slice is returned (in a newly copied slice).
|
||||
func OriginsFromArgsOrServerBlock(args, serverblock []string) []string {
|
||||
if len(args) == 0 {
|
||||
s := make([]string, len(serverblock))
|
||||
copy(s, serverblock)
|
||||
for i := range s {
|
||||
s[i] = Host(s[i]).NormalizeExact()[0] // expansion of these already happened in dnsserver/register.go
|
||||
}
|
||||
return s
|
||||
}
|
||||
s := []string{}
|
||||
for i := range args {
|
||||
sx := Host(args[i]).NormalizeExact()
|
||||
if len(sx) == 0 {
|
||||
continue // silently ignores errors.
|
||||
}
|
||||
s = append(s, sx...)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
38
vendor/github.com/coredns/coredns/plugin/pkg/cache/cache.go
generated
vendored
38
vendor/github.com/coredns/coredns/plugin/pkg/cache/cache.go
generated
vendored
@@ -45,9 +45,10 @@ func New(size int) *Cache {
|
||||
}
|
||||
|
||||
// Add adds a new element to the cache. If the element already exists it is overwritten.
|
||||
func (c *Cache) Add(key uint64, el interface{}) {
|
||||
// Returns true if an existing element was evicted to make room for this element.
|
||||
func (c *Cache) Add(key uint64, el interface{}) bool {
|
||||
shard := key & (shardSize - 1)
|
||||
c.shards[shard].Add(key, el)
|
||||
return c.shards[shard].Add(key, el)
|
||||
}
|
||||
|
||||
// Get looks up element index under key.
|
||||
@@ -71,22 +72,33 @@ func (c *Cache) Len() int {
|
||||
return l
|
||||
}
|
||||
|
||||
// Walk walks each shard in the cache.
|
||||
func (c *Cache) Walk(f func(map[uint64]interface{}, uint64) bool) {
|
||||
for _, s := range c.shards {
|
||||
s.Walk(f)
|
||||
}
|
||||
}
|
||||
|
||||
// newShard returns a new shard with size.
|
||||
func newShard(size int) *shard { return &shard{items: make(map[uint64]interface{}), size: size} }
|
||||
|
||||
// Add adds element indexed by key into the cache. Any existing element is overwritten
|
||||
func (s *shard) Add(key uint64, el interface{}) {
|
||||
// Returns true if an existing element was evicted to make room for this element.
|
||||
func (s *shard) Add(key uint64, el interface{}) bool {
|
||||
eviction := false
|
||||
s.Lock()
|
||||
if len(s.items) >= s.size {
|
||||
if _, ok := s.items[key]; !ok {
|
||||
for k := range s.items {
|
||||
delete(s.items, k)
|
||||
eviction = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
s.items[key] = el
|
||||
s.Unlock()
|
||||
return eviction
|
||||
}
|
||||
|
||||
// Remove removes the element indexed by key from the cache.
|
||||
@@ -122,4 +134,24 @@ func (s *shard) Len() int {
|
||||
return l
|
||||
}
|
||||
|
||||
// Walk walks the shard for each element the function f is executed while holding a write lock.
|
||||
func (s *shard) Walk(f func(map[uint64]interface{}, uint64) bool) {
|
||||
s.RLock()
|
||||
items := make([]uint64, len(s.items))
|
||||
i := 0
|
||||
for k := range s.items {
|
||||
items[i] = k
|
||||
i++
|
||||
}
|
||||
s.RUnlock()
|
||||
for _, k := range items {
|
||||
s.Lock()
|
||||
ok := f(s.items, k)
|
||||
s.Unlock()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const shardSize = 256
|
||||
|
83
vendor/github.com/coredns/coredns/plugin/pkg/cidr/cidr.go
generated
vendored
Normal file
83
vendor/github.com/coredns/coredns/plugin/pkg/cidr/cidr.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
// Package cidr contains functions that deal with classless reverse zones in the DNS.
|
||||
package cidr
|
||||
|
||||
import (
|
||||
"math"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/apparentlymart/go-cidr/cidr"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Split returns a slice of non-overlapping subnets that in union equal the subnet n,
|
||||
// and where each subnet falls on a reverse name segment boundary.
|
||||
// for ipv4 this is any multiple of 8 bits (/8, /16, /24 or /32)
|
||||
// for ipv6 this is any multiple of 4 bits
|
||||
func Split(n *net.IPNet) []string {
|
||||
boundary := 8
|
||||
nstr := n.String()
|
||||
if strings.Contains(nstr, ":") {
|
||||
boundary = 4
|
||||
}
|
||||
ones, _ := n.Mask.Size()
|
||||
if ones%boundary == 0 {
|
||||
return []string{n.String()}
|
||||
}
|
||||
|
||||
mask := int(math.Ceil(float64(ones)/float64(boundary))) * boundary
|
||||
networks := nets(n, mask)
|
||||
cidrs := make([]string, len(networks))
|
||||
for i := range networks {
|
||||
cidrs[i] = networks[i].String()
|
||||
}
|
||||
return cidrs
|
||||
}
|
||||
|
||||
// nets return a slice of prefixes with the desired mask subnetted from original network.
|
||||
func nets(network *net.IPNet, newPrefixLen int) []*net.IPNet {
|
||||
prefixLen, _ := network.Mask.Size()
|
||||
maxSubnets := int(math.Exp2(float64(newPrefixLen)) / math.Exp2(float64(prefixLen)))
|
||||
nets := []*net.IPNet{{network.IP, net.CIDRMask(newPrefixLen, 8*len(network.IP))}}
|
||||
|
||||
for i := 1; i < maxSubnets; i++ {
|
||||
next, exceeds := cidr.NextSubnet(nets[len(nets)-1], newPrefixLen)
|
||||
nets = append(nets, next)
|
||||
if exceeds {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nets
|
||||
}
|
||||
|
||||
// Reverse return the reverse zones that are authoritative for each net in ns.
|
||||
func Reverse(nets []string) []string {
|
||||
rev := make([]string, len(nets))
|
||||
for i := range nets {
|
||||
ip, n, _ := net.ParseCIDR(nets[i])
|
||||
r, err1 := dns.ReverseAddr(ip.String())
|
||||
if err1 != nil {
|
||||
continue
|
||||
}
|
||||
ones, bits := n.Mask.Size()
|
||||
// get the size, in bits, of each portion of hostname defined in the reverse address. (8 for IPv4, 4 for IPv6)
|
||||
sizeDigit := 8
|
||||
if len(n.IP) == net.IPv6len {
|
||||
sizeDigit = 4
|
||||
}
|
||||
// Get the first lower octet boundary to see what encompassing zone we should be authoritative for.
|
||||
mod := (bits - ones) % sizeDigit
|
||||
nearest := (bits - ones) + mod
|
||||
offset := 0
|
||||
var end bool
|
||||
for i := 0; i < nearest/sizeDigit; i++ {
|
||||
offset, end = dns.NextLabel(r, offset)
|
||||
if end {
|
||||
break
|
||||
}
|
||||
}
|
||||
rev[i] = r[offset:]
|
||||
}
|
||||
return rev
|
||||
}
|
5
vendor/github.com/coredns/coredns/plugin/pkg/doh/doh.go
generated
vendored
5
vendor/github.com/coredns/coredns/plugin/pkg/doh/doh.go
generated
vendored
@@ -5,7 +5,6 @@ import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
@@ -50,7 +49,6 @@ func NewRequest(method, url string, m *dns.Msg) (*http.Request, error) {
|
||||
default:
|
||||
return nil, fmt.Errorf("method not allowed: %s", method)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ResponseToMsg converts a http.Response to a dns message.
|
||||
@@ -72,7 +70,6 @@ func RequestToMsg(req *http.Request) (*dns.Msg, error) {
|
||||
default:
|
||||
return nil, fmt.Errorf("method not allowed: %s", req.Method)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// requestToMsgPost extracts the dns message from the request body.
|
||||
@@ -95,7 +92,7 @@ func requestToMsgGet(req *http.Request) (*dns.Msg, error) {
|
||||
}
|
||||
|
||||
func toMsg(r io.ReadCloser) (*dns.Msg, error) {
|
||||
buf, err := ioutil.ReadAll(r)
|
||||
buf, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
4
vendor/github.com/coredns/coredns/plugin/pkg/log/log.go
generated
vendored
4
vendor/github.com/coredns/coredns/plugin/pkg/log/log.go
generated
vendored
@@ -10,7 +10,7 @@ package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
golog "log"
|
||||
"os"
|
||||
"sync"
|
||||
@@ -102,7 +102,7 @@ func Fatal(v ...interface{}) { log(fatal, v...); os.Exit(1) }
|
||||
func Fatalf(format string, v ...interface{}) { logf(fatal, format, v...); os.Exit(1) }
|
||||
|
||||
// Discard sets the log output to /dev/null.
|
||||
func Discard() { golog.SetOutput(ioutil.Discard) }
|
||||
func Discard() { golog.SetOutput(io.Discard) }
|
||||
|
||||
const (
|
||||
debug = "[DEBUG] "
|
||||
|
6
vendor/github.com/coredns/coredns/plugin/pkg/parse/host.go
generated
vendored
6
vendor/github.com/coredns/coredns/plugin/pkg/parse/host.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
@@ -11,6 +12,9 @@ import (
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// ErrNoNameservers is returned by HostPortOrFile if no servers can be parsed.
|
||||
var ErrNoNameservers = errors.New("no nameservers found")
|
||||
|
||||
// Strips the zone, but preserves any port that comes after the zone
|
||||
func stripZone(host string) string {
|
||||
if strings.Contains(host, "%") {
|
||||
@@ -70,7 +74,7 @@ func HostPortOrFile(s ...string) ([]string, error) {
|
||||
servers = append(servers, h)
|
||||
}
|
||||
if len(servers) == 0 {
|
||||
return servers, fmt.Errorf("no nameservers found")
|
||||
return servers, ErrNoNameservers
|
||||
}
|
||||
return servers, nil
|
||||
}
|
||||
|
35
vendor/github.com/coredns/coredns/plugin/pkg/parse/parse.go
generated
vendored
35
vendor/github.com/coredns/coredns/plugin/pkg/parse/parse.go
generated
vendored
@@ -4,46 +4,35 @@ package parse
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||
|
||||
"github.com/caddyserver/caddy"
|
||||
)
|
||||
|
||||
// Transfer parses transfer statements: 'transfer [to|from] [address...]'.
|
||||
func Transfer(c *caddy.Controller, secondary bool) (tos, froms []string, err error) {
|
||||
// TransferIn parses transfer statements: 'transfer from [address...]'.
|
||||
func TransferIn(c *caddy.Controller) (froms []string, err error) {
|
||||
if !c.NextArg() {
|
||||
return nil, nil, c.ArgErr()
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
value := c.Val()
|
||||
switch value {
|
||||
case "to":
|
||||
tos = c.RemainingArgs()
|
||||
for i := range tos {
|
||||
if tos[i] != "*" {
|
||||
normalized, err := HostPort(tos[i], transport.Port)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
tos[i] = normalized
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, c.Errf("unknown property %s", value)
|
||||
case "from":
|
||||
if !secondary {
|
||||
return nil, nil, fmt.Errorf("can't use `transfer from` when not being a secondary")
|
||||
}
|
||||
froms = c.RemainingArgs()
|
||||
if len(froms) == 0 {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
for i := range froms {
|
||||
if froms[i] != "*" {
|
||||
normalized, err := HostPort(froms[i], transport.Port)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
froms[i] = normalized
|
||||
} else {
|
||||
return nil, nil, fmt.Errorf("can't use '*' in transfer from")
|
||||
return nil, fmt.Errorf("can't use '*' in transfer from")
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
return froms, nil
|
||||
}
|
||||
|
1
vendor/github.com/coredns/coredns/plugin/pkg/trace/trace.go
generated
vendored
1
vendor/github.com/coredns/coredns/plugin/pkg/trace/trace.go
generated
vendored
@@ -2,6 +2,7 @@ package trace
|
||||
|
||||
import (
|
||||
"github.com/coredns/coredns/plugin"
|
||||
|
||||
ot "github.com/opentracing/opentracing-go"
|
||||
)
|
||||
|
||||
|
5
vendor/github.com/coredns/coredns/plugin/plugin.go
generated
vendored
5
vendor/github.com/coredns/coredns/plugin/plugin.go
generated
vendored
@@ -69,7 +69,7 @@ func (f HandlerFunc) Name() string { return "handlerfunc" }
|
||||
// Error returns err with 'plugin/name: ' prefixed to it.
|
||||
func Error(name string, err error) error { return fmt.Errorf("%s/%s: %s", "plugin", name, err) }
|
||||
|
||||
// NextOrFailure calls next.ServeDNS when next is not nil, otherwise it will return, a ServerFailure and a nil error.
|
||||
// NextOrFailure calls next.ServeDNS when next is not nil, otherwise it will return, a ServerFailure and a `no next plugin found` error.
|
||||
func NextOrFailure(name string, next Handler, ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { // nolint: golint
|
||||
if next != nil {
|
||||
if span := ot.SpanFromContext(ctx); span != nil {
|
||||
@@ -105,5 +105,8 @@ const Namespace = "coredns"
|
||||
// TimeBuckets is based on Prometheus client_golang prometheus.DefBuckets
|
||||
var TimeBuckets = prometheus.ExponentialBuckets(0.00025, 2, 16) // from 0.25ms to 8 seconds
|
||||
|
||||
// SlimTimeBuckets is low cardinality set of duration buckets.
|
||||
var SlimTimeBuckets = prometheus.ExponentialBuckets(0.00025, 10, 5) // from 0.25ms to 2.5 seconds
|
||||
|
||||
// ErrOnce is returned when a plugin doesn't support multiple setups per server.
|
||||
var ErrOnce = errors.New("this plugin can only be used once per Server Block")
|
||||
|
2
vendor/github.com/coredns/coredns/plugin/register.go
generated
vendored
2
vendor/github.com/coredns/coredns/plugin/register.go
generated
vendored
@@ -1,6 +1,6 @@
|
||||
package plugin
|
||||
|
||||
import "github.com/caddyserver/caddy"
|
||||
import "github.com/coredns/caddy"
|
||||
|
||||
// Register registers your plugin with CoreDNS and allows it to be called when the server is running.
|
||||
func Register(name string, action caddy.SetupFunc) {
|
||||
|
13
vendor/github.com/coredns/coredns/plugin/test/file.go
generated
vendored
13
vendor/github.com/coredns/coredns/plugin/test/file.go
generated
vendored
@@ -1,18 +1,17 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// TempFile will create a temporary file on disk and returns the name and a cleanup function to remove it later.
|
||||
func TempFile(dir, content string) (string, func(), error) {
|
||||
f, err := ioutil.TempFile(dir, "go-test-tmpfile")
|
||||
f, err := os.CreateTemp(dir, "go-test-tmpfile")
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if err := ioutil.WriteFile(f.Name(), []byte(content), 0644); err != nil {
|
||||
if err := os.WriteFile(f.Name(), []byte(content), 0644); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
rmFunc := func() { os.Remove(f.Name()) }
|
||||
@@ -21,7 +20,7 @@ func TempFile(dir, content string) (string, func(), error) {
|
||||
|
||||
// WritePEMFiles creates a tmp dir with ca.pem, cert.pem, and key.pem and the func to remove it
|
||||
func WritePEMFiles(dir string) (string, func(), error) {
|
||||
tempDir, err := ioutil.TempDir(dir, "go-test-pemfiles")
|
||||
tempDir, err := os.MkdirTemp(dir, "go-test-pemfiles")
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@@ -45,7 +44,7 @@ xGbtCkhVk2VQ+BiCWnjYXJ6ZMzabP7wiOFDP9Pvr2ik22PRItsW/TLfHFXM1jDmc
|
||||
I1rs/VUGKzcJGVIWbHrgjP68CTStGAvKgbsTqw7aLXTSqtPw88N9XVSyRg==
|
||||
-----END CERTIFICATE-----`
|
||||
path := filepath.Join(tempDir, "ca.pem")
|
||||
if err := ioutil.WriteFile(path, []byte(data), 0644); err != nil {
|
||||
if err := os.WriteFile(path, []byte(data), 0644); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
data = `-----BEGIN CERTIFICATE-----
|
||||
@@ -66,7 +65,7 @@ zhDEPP4FhY+Sz+y1yWirphl7A1aZwhXVPcfWIGqpQ3jzNwUeocbH27kuLh+U4hQo
|
||||
qeg10RdFnw==
|
||||
-----END CERTIFICATE-----`
|
||||
path = filepath.Join(tempDir, "cert.pem")
|
||||
if err = ioutil.WriteFile(path, []byte(data), 0644); err != nil {
|
||||
if err = os.WriteFile(path, []byte(data), 0644); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
@@ -98,7 +97,7 @@ E/WObVJXDnBdViu0L9abE9iaTToBVri4cmlDlZagLuKVR+TFTCN/DSlVZTDkqkLI
|
||||
8chzqtkH6b2b2R73hyRysWjsomys34ma3mEEPTX/aXeAF2MSZ/EWT9yL
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
path = filepath.Join(tempDir, "key.pem")
|
||||
if err = ioutil.WriteFile(path, []byte(data), 0644); err != nil {
|
||||
if err = os.WriteFile(path, []byte(data), 0644); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
|
24
vendor/github.com/coredns/coredns/plugin/test/helpers.go
generated
vendored
24
vendor/github.com/coredns/coredns/plugin/test/helpers.go
generated
vendored
@@ -29,14 +29,15 @@ func (p RRSet) Less(i, j int) bool { return p[i].String() < p[j].String() }
|
||||
// Case represents a test case that encapsulates various data from a query and response.
|
||||
// Note that is the TTL of a record is 303 we don't compare it with the TTL.
|
||||
type Case struct {
|
||||
Qname string
|
||||
Qtype uint16
|
||||
Rcode int
|
||||
Do bool
|
||||
Answer []dns.RR
|
||||
Ns []dns.RR
|
||||
Extra []dns.RR
|
||||
Error error
|
||||
Qname string
|
||||
Qtype uint16
|
||||
Rcode int
|
||||
Do bool
|
||||
AuthenticatedData bool
|
||||
Answer []dns.RR
|
||||
Ns []dns.RR
|
||||
Extra []dns.RR
|
||||
Error error
|
||||
}
|
||||
|
||||
// Msg returns a *dns.Msg embedded in c.
|
||||
@@ -99,6 +100,9 @@ func DNSKEY(rr string) *dns.DNSKEY { r, _ := dns.NewRR(rr); return r.(*dns.DNSKE
|
||||
// DS returns a DS record from rr. It panics on errors.
|
||||
func DS(rr string) *dns.DS { r, _ := dns.NewRR(rr); return r.(*dns.DS) }
|
||||
|
||||
// NAPTR returns a NAPTR record from rr. It panics on errors.
|
||||
func NAPTR(rr string) *dns.NAPTR { r, _ := dns.NewRR(rr); return r.(*dns.NAPTR) }
|
||||
|
||||
// OPT returns an OPT record with UDP buffer size set to bufsize and the DO bit set to do.
|
||||
func OPT(bufsize int, do bool) *dns.OPT {
|
||||
o := new(dns.OPT)
|
||||
@@ -112,7 +116,7 @@ func OPT(bufsize int, do bool) *dns.OPT {
|
||||
return o
|
||||
}
|
||||
|
||||
// Header test if the header in resp matches the header as defined in tc.
|
||||
// Header tests if the header in resp matches the header as defined in tc.
|
||||
func Header(tc Case, resp *dns.Msg) error {
|
||||
if resp.Rcode != tc.Rcode {
|
||||
return fmt.Errorf("rcode is %q, expected %q", dns.RcodeToString[resp.Rcode], dns.RcodeToString[tc.Rcode])
|
||||
@@ -248,7 +252,7 @@ func Section(tc Case, sec sect, rr []dns.RR) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CNAMEOrder makes sure that CNAMES do not appear after their target records
|
||||
// CNAMEOrder makes sure that CNAMES do not appear after their target records.
|
||||
func CNAMEOrder(res *dns.Msg) error {
|
||||
for i, c := range res.Answer {
|
||||
if c.Header().Rrtype != dns.TypeCNAME {
|
||||
|
12
vendor/github.com/coredns/coredns/plugin/test/responsewriter.go
generated
vendored
12
vendor/github.com/coredns/coredns/plugin/test/responsewriter.go
generated
vendored
@@ -38,22 +38,22 @@ func (t *ResponseWriter) RemoteAddr() net.Addr {
|
||||
return &net.UDPAddr{IP: ip, Port: port, Zone: ""}
|
||||
}
|
||||
|
||||
// WriteMsg implement dns.ResponseWriter interface.
|
||||
// WriteMsg implements dns.ResponseWriter interface.
|
||||
func (t *ResponseWriter) WriteMsg(m *dns.Msg) error { return nil }
|
||||
|
||||
// Write implement dns.ResponseWriter interface.
|
||||
// Write implements dns.ResponseWriter interface.
|
||||
func (t *ResponseWriter) Write(buf []byte) (int, error) { return len(buf), nil }
|
||||
|
||||
// Close implement dns.ResponseWriter interface.
|
||||
// Close implements dns.ResponseWriter interface.
|
||||
func (t *ResponseWriter) Close() error { return nil }
|
||||
|
||||
// TsigStatus implement dns.ResponseWriter interface.
|
||||
// TsigStatus implements dns.ResponseWriter interface.
|
||||
func (t *ResponseWriter) TsigStatus() error { return nil }
|
||||
|
||||
// TsigTimersOnly implement dns.ResponseWriter interface.
|
||||
// TsigTimersOnly implements dns.ResponseWriter interface.
|
||||
func (t *ResponseWriter) TsigTimersOnly(bool) {}
|
||||
|
||||
// Hijack implement dns.ResponseWriter interface.
|
||||
// Hijack implements dns.ResponseWriter interface.
|
||||
func (t *ResponseWriter) Hijack() {}
|
||||
|
||||
// ResponseWriter6 returns fixed client and remote address in IPv6. The remote
|
||||
|
2
vendor/github.com/coredns/coredns/plugin/test/scrape.go
generated
vendored
2
vendor/github.com/coredns/coredns/plugin/test/scrape.go
generated
vendored
@@ -77,7 +77,7 @@ func Scrape(url string) []*MetricFamily {
|
||||
return result
|
||||
}
|
||||
|
||||
// ScrapeMetricAsInt provide a sum of all metrics collected for the name and label provided.
|
||||
// ScrapeMetricAsInt provides a sum of all metrics collected for the name and label provided.
|
||||
// if the metric is not a numeric value, it will be counted a 0.
|
||||
func ScrapeMetricAsInt(addr string, name string, label string, nometricvalue int) int {
|
||||
|
||||
|
4
vendor/github.com/coredns/coredns/request/request.go
generated
vendored
4
vendor/github.com/coredns/coredns/request/request.go
generated
vendored
@@ -144,7 +144,7 @@ func (r *Request) Family() int {
|
||||
return 2
|
||||
}
|
||||
|
||||
// Do returns if the request has the DO (DNSSEC OK) bit set.
|
||||
// Do returns true if the request has the DO (DNSSEC OK) bit set.
|
||||
func (r *Request) Do() bool {
|
||||
if r.size != 0 {
|
||||
return r.do
|
||||
@@ -338,6 +338,8 @@ func (r *Request) Clear() {
|
||||
r.port = ""
|
||||
r.localPort = ""
|
||||
r.family = 0
|
||||
r.size = 0
|
||||
r.do = false
|
||||
}
|
||||
|
||||
// Match checks if the reply matches the qname and qtype from the request, it returns
|
||||
|
Reference in New Issue
Block a user