1
0
mirror of https://github.com/taigrr/godns synced 2025-01-18 04:03:25 -08:00

Compare commits

..

No commits in common. "master" and "V1.6.1" have entirely different histories.

328 changed files with 170097 additions and 2099 deletions

12
.github/FUNDING.yml vendored
View File

@ -1,12 +0,0 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://www.paypal.me/timothyye

View File

@ -1,20 +0,0 @@
name: Go
on: [push]
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.15.7
uses: actions/setup-go@v1
with:
go-version: 1.15.7
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v1
- name: Build
run: cd cmd/godns && go build -v .

4
.gitignore vendored
View File

@ -28,9 +28,7 @@ config.json
*.log *.log
*.swp *.swp
*.gz *.gz
godns cmd/godns/godns
godns.exe
config.json
cmd/godns/config.json cmd/godns/config.json
/.idea /.idea

17
.travis.yml Normal file
View File

@ -0,0 +1,17 @@
language: go
go:
- 1.7.x
- 1.8.x
- 1.9.x
- 1.10.x
install:
- go get -v
- go get -v github.com/bitly/go-simplejson
- go get -v github.com/fatih/color
- go get -u github.com/alecthomas/gometalinter
script:
- gometalinter --install
- gometalinter --config=./gometalinter.json --vendor ./...
- cp ./config_sample.json ./config.json
- go test -v ./...

View File

@ -1,76 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at i@xiaozhou.net. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

View File

@ -1,9 +0,0 @@
FROM golang:alpine AS builder
RUN mkdir /godns
ADD . /godns/
WORKDIR /godns
RUN CGO_ENABLED=0 go build -o godns cmd/godns/godns.go
FROM gcr.io/distroless/base
COPY --from=builder /godns/godns /godns
ENTRYPOINT ["/godns"]

81
Gopkg.lock generated Normal file
View File

@ -0,0 +1,81 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
digest = "1:b520b55fc1146c5b0eea03b07233f7a3d4a9be985c037c91ea6b82ecb81bd521"
name = "github.com/bitly/go-simplejson"
packages = ["."]
pruneopts = "UT"
revision = "aabad6e819789e569bd6aabf444c935aa9ba1e44"
version = "v0.5.0"
[[projects]]
digest = "1:865079840386857c809b72ce300be7580cb50d3d3129ce11bf9aa6ca2bc1934a"
name = "github.com/fatih/color"
packages = ["."]
pruneopts = "UT"
revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4"
version = "v1.7.0"
[[projects]]
digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67"
name = "github.com/mattn/go-colorable"
packages = ["."]
pruneopts = "UT"
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
version = "v0.0.9"
[[projects]]
digest = "1:d4d17353dbd05cb52a2a52b7fe1771883b682806f68db442b436294926bbfafb"
name = "github.com/mattn/go-isatty"
packages = ["."]
pruneopts = "UT"
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
[[projects]]
branch = "master"
digest = "1:8c520a50d95df847d7732e971616b443afb0d95c3be465e3952bfde515d4e47a"
name = "golang.org/x/net"
packages = [
"internal/socks",
"proxy",
]
pruneopts = "UT"
revision = "faa378e6dbaed88bd8100f8bcf09939375c6e8fa"
[[projects]]
branch = "master"
digest = "1:4dcdb3f7c22f5f048de7c7ad5b72c4547d63bfb4923da15538d0051d553b2ef8"
name = "golang.org/x/sys"
packages = ["unix"]
pruneopts = "UT"
revision = "11551d06cbcc94edc80a0facaccbda56473c19c1"
[[projects]]
branch = "v3"
digest = "1:7388652e2215a3f45d341d58766ed58317971030eb1cbd75f005f96ace8e9196"
name = "gopkg.in/alexcesaro/quotedprintable.v3"
packages = ["."]
pruneopts = "UT"
revision = "2caba252f4dc53eaf6b553000885530023f54623"
[[projects]]
digest = "1:eebd52aee67d9f1e0af1859a584e14b1817581dd5f90d4585418c27b6a93c966"
name = "gopkg.in/gomail.v2"
packages = ["."]
pruneopts = "UT"
revision = "41f3572897373c5538c50a2402db15db079fa4fd"
version = "2.0.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
"github.com/bitly/go-simplejson",
"github.com/fatih/color",
"golang.org/x/net/proxy",
"gopkg.in/gomail.v2",
]
solver-name = "gps-cdcl"
solver-version = 1

46
Gopkg.toml Normal file
View File

@ -0,0 +1,46 @@
# Gopkg.toml example
#
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
[[constraint]]
name = "github.com/bitly/go-simplejson"
version = "0.5.0"
[[constraint]]
name = "github.com/fatih/color"
version = "1.7.0"
[[constraint]]
branch = "master"
name = "golang.org/x/net"
[[constraint]]
name = "gopkg.in/gomail.v2"
version = "2.0.0"
[prune]
go-tests = true
unused-packages = true

View File

@ -1,44 +0,0 @@
# Binary name
BINARY=godns
# Builds the project
build:
GO111MODULE=on go build -ldflags "-X main.Version=${VERSION}" -o ${BINARY} cmd/godns/godns.go
# Installs our project: copies binaries
install:
GO111MODULE=on go install
image:
# Build docker image
go clean
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t timothyye/godns:${VERSION} . --push
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t timothyye/godns:latest . --push
release:
# Clean
go clean
rm -rf *.gz
# Build for mac
GO111MODULE=on go build -ldflags "-s -w -X main.Version=${VERSION}" cmd/godns/godns.go
tar czvf ${BINARY}-mac64-${VERSION}.tar.gz ./${BINARY}
# Build for linux
go clean
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -ldflags "-s -w -X main.Version=${VERSION}" cmd/godns/godns.go
tar czvf ${BINARY}-linux64-${VERSION}.tar.gz ./${BINARY}
# Build for arm
go clean
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GO111MODULE=on go build -ldflags "-s -w -X main.Version=${VERSION}" cmd/godns/godns.go
tar czvf ${BINARY}-arm64-${VERSION}.tar.gz ./${BINARY}
go clean
CGO_ENABLED=0 GOOS=linux GOARCH=arm GO111MODULE=on go build -ldflags "-s -w -X main.Version=${VERSION}" cmd/godns/godns.go
tar czvf ${BINARY}-arm-${VERSION}.tar.gz ./${BINARY}
# Build for win
go clean
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 GO111MODULE=on go build -ldflags "-s -w -X main.Version=${VERSION}" cmd/godns/godns.go
tar czvf ${BINARY}-win64-${VERSION}.tar.gz ./${BINARY}.exe
make image
# Cleans our projects: deletes binaries
clean:
go clean
rm -rf ./godns
rm -rf ./godns.exe
rm -rf *.gz
.PHONY: clean build

547
README.md
View File

@ -7,8 +7,10 @@
╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝
``` ```
[![Apache licensed][9]][10] [![Docker][3]][4] [![Go Report Card][11]][12] [![Cover.Run][15]][16] [![GoDoc][13]][14] [![MIT licensed][9]][10] [![Build Status][1]][2] [![Docker][3]][4] [![Go Report Card][11]][12] [![Cover.Run][15]][16] [![GoDoc][13]][14]
[1]: https://travis-ci.org/TimothyYe/godns.svg?branch=master
[2]: https://travis-ci.org/TimothyYe/godns
[3]: https://images.microbadger.com/badges/image/timothyye/godns.svg [3]: https://images.microbadger.com/badges/image/timothyye/godns.svg
[4]: https://microbadger.com/images/timothyye/godns [4]: https://microbadger.com/images/timothyye/godns
[9]: https://img.shields.io/badge/license-Apache-blue.svg [9]: https://img.shields.io/badge/license-Apache-blue.svg
@ -20,152 +22,86 @@
[15]: https://img.shields.io/badge/cover.run-88.2%25-green.svg [15]: https://img.shields.io/badge/cover.run-88.2%25-green.svg
[16]: https://cover.run/go/github.com/timothyye/godns [16]: https://cover.run/go/github.com/timothyye/godns
[GoDNS](https://github.com/TimothyYe/godns) is a dynamic DNS (DDNS) client tool. It is a rewrite in [Go](https://golang.org) of my early [DynDNS](https://github.com/TimothyYe/DynDNS) open source project. GoDNS is a dynamic DNS (DDNS) client tool, it is based on my early open source project: [DynDNS](https://github.com/TimothyYe/DynDNS).
Currently supports updating A records for subdomains. Doesn't support updating of root domains. Now I rewrite [DynDNS](https://github.com/TimothyYe/DynDNS) by Golang and call it [GoDNS](https://github.com/TimothyYe/godns).
--- ## Supported DNS Provider
- [Supported DNS Providers](#supported-dns-providers) * Cloudflare ([https://cloudflare.com](https://cloudflare.com))
- [Supported Platforms](#supported-platforms) * DNSPod ([https://www.dnspod.cn/](https://www.dnspod.cn/))
- [Pre-conditions](#pre-conditions) * HE.net (Hurricane Electric) ([https://dns.he.net/](https://dns.he.net/))
- [Installation](#installation)
- [Usage](#usage)
- [Configuration](#configuration)
- [Overview](#overview)
- [Configuration properties](#configuration-properties)
- [Configuration examples](#configuration-examples)
- [Cloudflare](#cloudflare)
- [DNSPod](#dnspod)
- [Dreamhost](#dreamhost)
- [Google Domains](#google-domains)
- [AliDNS](#alidns)
- [DuckDNS](#duckdns)
- [No-IP](#no-ip)
- [HE.net](#henet)
- [Notifications](#notifications)
- [Email](#email)
- [Telegram](#telegram)
- [Slack](#slack)
- [Miscellaneous topics](#miscellaneous-topics)
- [IPv6 support](#ipv6-support)
- [Network interface IP address](#network-interface-ip-address)
- [SOCKS5 proxy support](#socks5-proxy-support)
- [Running GoDNS](#running-godns)
- [As a manual daemon](#as-a-manual-daemon)
- [As a managed daemon (with upstart)](#as-a-managed-daemon-with-upstart)
- [As a managed daemon (with systemd)](#as-a-managed-daemon-with-systemd)
- [As a Docker container](#as-a-docker-container)
- [As a Windows service](#as-a-windows-service)
- [Special Thanks](#special-thanks)
---
## Supported DNS Providers
| Provider | IPv4 support | IPv6 support | Root Domain | Subdomains |
| ------------------------------------- | :----------------: | :----------------: | :----------------: | :----------------: |
| [Cloudflare][cloudflare] | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| [Google Domains][google.domains] | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: |
| [DNSPod][dnspod] | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: |
| [HE.net (Hurricane Electric)][he.net] | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: |
| [AliDNS][alidns] | :white_check_mark: | :x: | :x: | :white_check_mark: |
| [DuckDNS][duckdns] | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: |
| [Dreamhost][dreamhost] | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: |
| [No-IP][no-ip] | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: |
[cloudflare]: https://cloudflare.com
[google.domains]: https://domains.google
[dnspod]: https://www.dnspod.cn
[he.net]: https://dns.he.net
[alidns]: https://help.aliyun.com/product/29697.html
[duckdns]: https://www.duckdns.org
[dreamhost]: https://www.dreamhost.com
[no-ip]: https://www.noip.com
Tip: You can follow this [issue](https://github.com/TimothyYe/godns/issues/76) to view the current status of DDNS for root domains.
## Supported Platforms ## Supported Platforms
* Linux * Linux
* MacOS * MacOS
* ARM Linux (Raspberry Pi, etc.) * ARM Linux (Raspberry Pi, etc...)
* Windows * Windows
* MIPS32 platform * MIPS32 platform
To compile binaries for MIPS (mips or mipsle), run: ## MIPS32 platform
```bash To compile binaries for MIPS (mips or mipsle):
```
GOOS=linux GOARCH=mips/mipsle GOMIPS=softfloat go build -a GOOS=linux GOARCH=mips/mipsle GOMIPS=softfloat go build -a
``` ```
The binary can run on routers as well. And the binary can run well on routers.
## Pre-conditions ## Pre-condition
To use GoDNS, it is assumed: * Register and own a domain.
* You registered (now own) a domain
* Domain was delegated to a supported [DNS provider](#supported-dns-providers) (i.e. it has nameserver `NS` records pointing at a supported provider)
Alternatively, you can sign in to [DuckDNS](https://www.duckdns.org) (with a social account) and get a subdomain on the duckdns.org domain for free. * Domain's nameserver points to [DNSPod](https://www.dnspod.cn/) or [HE.net](https://dns.he.net/) or [Cloudflare](https://www.cloudflare.com/).
## Installation ## Get it
Build GoDNS by running (from the root of the repository): ### Build it from source code
* Get source code from Github:
```bash ```bash
cd cmd/godns # go to the GoDNS directory git clone https://github.com/timothyye/godns.git
go get -v # get dependencies ```
go build # build * Go into the godns directory, get related library and then build it:
```bash
cd cmd/godns
go get -v
go build
``` ```
You can also download a compiled binary from the [releases](https://github.com/TimothyYe/godns/releases). ### Download from releases
## Usage
Print usage/help by running: Download compiled binaries from [releases](https://github.com/TimothyYe/godns/releases)
## Get help
```bash ```bash
$ ./godns -h $ ./godns -h
Usage of ./godns: Usage of ./godns:
-c string -c string
Specify a config file (default "./config.json") Specify a config file (default "./config.json")
-d Run it as docker mode
-h Show help -h Show help
``` ```
## Configuration ## Config it
### Overview * Get [config_sample.json](https://github.com/timothyye/godns/blob/master/config_sample.json) from Github.
* Rename it to **config.json**.
* Configure your provider, domain/sub-domain info, username and password, etc.
* Configure the SMTP options if you want, a mail notification will sent to your mailbox once the IP is changed.
* Save it in the same directory of GoDNS, or use -c=your_conf_path command.
* Make a copy of [config_sample.json](./config_sample.json) and name it `config.json` ### Config example for Cloudflare
* Configure your provider, domain/subdomain info, credentials, etc.
* Configure a notification medium (e.g. SMTP to receive emails) to get notified when your IP address changes
* Place the file in the same directory of GoDNS or use the `-c=path/to/your/file.json` option
### Configuration properties For Cloudflare, you need to provide email & Global API Key as password, and config all the domains & subdomains.
* `provider` — One of the [supported provider to use](#supported-dns-providers): `Cloudflare`, `Google`, `DNSPod`, `AliDNS`, `HE`, `DuckDNS` or `Dreamhost`.
* `email` — Email or account name of the DNS provider.
* `password` — Password of the DNS provider.
* `login_token` — API token of the DNS provider.
* `domains` — Domains list, with your sub domains.
* `ip_url` — A URL for fetching one's public IPv4 address.
* `ipv6_url` — A URL for fetching one's public IPv6 address.
* `ip_type` — Switch deciding if IPv4 or IPv6 should be used (when [supported](#supported-dns-providers)). Available values: `IPv4` or `IPv6`.
* `interval` — How often (in seconds) the public IP should be updated.
* `socks5_proxy` — Socks5 proxy server.
* `resolver` — Address of a public DNS server to use. For instance to use [Google's public DNS](https://developers.google.com/speed/public-dns/docs/using), you can set `8.8.8.8` when using GoDNS in IPv4 mode or `2001:4860:4860::8888` in IPv6 mode.
### Configuration examples
#### Cloudflare
For Cloudflare, you need to provide the email & Global API Key as password (or to use the API token) and config all the domains & subdomains.
<details>
<summary>Using email & Global API Key</summary>
```json ```json
{ {
"provider": "Cloudflare", "provider": "Cloudflare",
"email": "you@example.com", "email": "you@example.com"
"password": "Global API Key", "password": "Global API Key",
"domains": [{ "domains": [{
"domain_name": "example.com", "domain_name": "example.com",
@ -175,47 +111,19 @@ For Cloudflare, you need to provide the email & Global API Key as password (or t
"sub_domains": ["www","test"] "sub_domains": ["www","test"]
} }
], ],
"resolver": "8.8.8.8", "ip_url": "https://ifconfig.co/ip",
"ip_url": "https://myip.biturl.top",
"interval": 300,
"socks5_proxy": "" "socks5_proxy": ""
} }
``` ```
</details>
<details> ### Config example for DNSPod
<summary>Using the API Token</summary>
```json For DNSPod, you need to provide email & password, and config all the domains & subdomains.
{
"provider": "Cloudflare",
"login_token": "API Token",
"domains": [{
"domain_name": "example.com",
"sub_domains": ["www","test"]
},{
"domain_name": "example2.com",
"sub_domains": ["www","test"]
}
],
"resolver": "8.8.8.8",
"ip_url": "https://myip.biturl.top",
"interval": 300,
"socks5_proxy": ""
}
```
</details>
#### DNSPod
For DNSPod, you need to provide your API Token(you can create it [here](https://www.dnspod.cn/console/user/security)), and config all the domains & subdomains.
<details>
<summary>Example</summary>
```json ```json
{ {
"provider": "DNSPod", "provider": "DNSPod",
"password": "",
"login_token": "your_id,your_token", "login_token": "your_id,your_token",
"domains": [{ "domains": [{
"domain_name": "example.com", "domain_name": "example.com",
@ -225,161 +133,14 @@ For DNSPod, you need to provide your API Token(you can create it [here](https://
"sub_domains": ["www","test"] "sub_domains": ["www","test"]
} }
], ],
"resolver": "8.8.8.8", "ip_url": "http://members.3322.org/dyndns/getip",
"ip_url": "https://myip.biturl.top",
"ip_type": "IPV4",
"interval": 300,
"socks5_proxy": "" "socks5_proxy": ""
} }
``` ```
</details> ### Config example for HE.net
#### Dreamhost
For Dreamhost, you need to provide your API Token(you can create it [here](https://panel.dreamhost.com/?tree=home.api)), and config all the domains & subdomains.
<details>
<summary>Example</summary>
```json
{
"provider": "Dreamhost",
"login_token": "your_api_key",
"domains": [{
"domain_name": "example.com",
"sub_domains": ["www","test"]
},{
"domain_name": "example2.com",
"sub_domains": ["www","test"]
}
],
"resolver": "8.8.8.8",
"ip_url": "https://myip.biturl.top",
"ip_type": "IPV4",
"interval": 300,
"resolver": "ns1.dreamhost.com",
"socks5_proxy": ""
}
```
</details>
#### Google Domains
For Google Domains, you need to provide email & password, and config all the domains & subdomains.
<details>
<summary>Example</summary>
```json
{
"provider": "Google",
"email": "Your_Username",
"password": "Your_Password",
"domains": [{
"domain_name": "example.com",
"sub_domains": ["www","test"]
},{
"domain_name": "example2.com",
"sub_domains": ["www","test"]
}
],
"resolver": "8.8.8.8",
"ip_url": "https://myip.biturl.top",
"interval": 300,
"socks5_proxy": ""
}
```
</details>
#### AliDNS
For AliDNS, you need to provide `AccessKeyID` & `AccessKeySecret` as `email` & `password`, and config all the domains & subdomains.
<details>
<summary>Example</summary>
```json
{
"provider": "AliDNS",
"email": "AccessKeyID",
"password": "AccessKeySecret",
"login_token": "",
"domains": [{
"domain_name": "example.com",
"sub_domains": ["www","test"]
},{
"domain_name": "example2.com",
"sub_domains": ["www","test"]
}
],
"resolver": "8.8.8.8",
"ip_url": "https://myip.biturl.top",
"interval": 300,
"socks5_proxy": ""
}
```
</details>
#### DuckDNS
For DuckDNS, only need to provide the `token`, config 1 default domain & subdomains.
<details>
<summary>Example</summary>
```json
{
"provider": "DuckDNS",
"password": "",
"login_token": "3aaaaaaaa-f411-4198-a5dc-8381cac61b87",
"domains": [
{
"domain_name": "www.duckdns.org",
"sub_domains": [
"myname"
]
}
],
"resolver": "8.8.8.8",
"ip_url": "https://myip.biturl.top",
"interval": 300,
"socks5_proxy": ""
}
```
</details>
#### No-IP
<details>
<summary>Example</summary>
```json
{
"provider": "NoIP",
"email": "mail@example.com",
"password": "YourPassword",
"domains": [
{
"domain_name": "ddns.net",
"sub_domains": ["timothyye6"]
}
],
"ip_type": "IPv4",
"ip_url": "https://myip.biturl.top",
"resolver": "8.8.8.8",
"interval": 300,
"socks5_proxy": ""
}
```
</details>
#### HE.net
For HE, email is not needed, just fill DDNS key to password, and config all the domains & subdomains. For HE, email is not needed, just fill DDNS key to password, and config all the domains & subdomains.
<details>
<summary>Example</summary>
```json ```json
{ {
"provider": "HE", "provider": "HE",
@ -393,41 +154,44 @@ For HE, email is not needed, just fill DDNS key to password, and config all the
"sub_domains": ["www","test"] "sub_domains": ["www","test"]
} }
], ],
"resolver": "8.8.8.8", "ip_url": "http://members.3322.org/dyndns/getip",
"ip_url": "https://myip.biturl.top",
"interval": 300,
"socks5_proxy": "" "socks5_proxy": ""
} }
``` ```
</details>
<details> ### HE.net DDNS configuration
<summary>Provider configuration</summary>
Add a new "A record" and make sure that "Enable entry for dynamic dns" is checked: Add a new "A record", make sure that "Enable entry for dynamic dns" is checked:
<img src="./snapshots/he1.png" width="640" /> <img src="https://github.com/TimothyYe/godns/blob/master/snapshots/he1.png?raw=true" width="640" />
Fill in your own DDNS key or generate a random DDNS key for this new created "A record": Fill your own DDNS key or generate a random DDNS key for this new created "A record":
<img src="./snapshots/he2.png" width="640" /> <img src="https://github.com/TimothyYe/godns/blob/master/snapshots/he2.png?raw=true" width="640" />
Remember the DDNS key and set it in the `password` property in the configuration file. Remember the DDNS key and fill it as password to the config.json.
__NOTICE__: If you have multiple domains or subdomains, make sure their DDNS key are the same. __NOTICE__: If you have multiple domains or subdomains, make sure their DDNS key are the same.
</details>
### Notifications ### Get an IP address from the interface
GoDNS can send a notification each time the IP changes. For some reasons if you want to get an IP directly from the interface, say `eth0` for Linux or `Local Area Connection` for Windows, update config file like this:
```json
"ip_url": "",
"ip_interface": "eth0",
```
#### Email If you set both `ip_url` and `ip_interface`, it first tries to get an IP address online, and if not succeed, gets
an IP address from the interface as a fallback.
Emails are sent over [SMTP](https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol). Update your configuration with the following snippet: Note that IPv6 address will be ignored currently.
### Email notification support
Update config file and provide your SMTP options, a notification mail will be sent to your mailbox once the IP is changed and updated.
```json ```json
"notify": { "notify": {
"mail": {
"enabled": true, "enabled": true,
"smtp_server": "smtp.example.com", "smtp_server": "smtp.example.com",
"smtp_username": "user", "smtp_username": "user",
@ -435,185 +199,66 @@ Emails are sent over [SMTP](https://en.wikipedia.org/wiki/Simple_Mail_Transfer_P
"smtp_port": 25, "smtp_port": 25,
"send_to": "my_mail@example.com" "send_to": "my_mail@example.com"
} }
}
``` ```
Each time the IP changes, you will receive an email like that: Notification mail example:
<img src="https://github.com/TimothyYe/godns/blob/master/snapshots/mail.png?raw=true" /> <img src="https://github.com/TimothyYe/godns/blob/master/snapshots/mail.png?raw=true" />
#### Telegram ### SOCKS5 proxy support
To receive a [Telegram](https://telegram.org/) message each time the IP changes, update your configuration with the following snippet: You can also use SOCKS5 proxy, just fill SOCKS5 address to the ```socks5_proxy``` item:
```json ```json
"notify": {
"telegram": {
"enabled": true,
"bot_api_key": "11111:aaaa-bbbb",
"chat_id": "-123456",
"message_template": "Domain *{{ .Domain }}* is updated to %0A{{ .CurrentIP }}",
"use_proxy": false
},
}
```
The `message_template` property supports [markdown](https://www.markdownguide.org). New lines needs to be escaped with `%0A`.
#### Slack
To receive a [Slack](https://slack.com) message each time the IP changes, update your configuration with the following snippet:
```json
"notify": {
"slack": {
"enabled": true,
"bot_api_token": "xoxb-xxx",
"channel": "your_channel",
"message_template": "Domain *{{ .Domain }}* is updated to \n{{ .CurrentIP }}",
"use_proxy": false
},
}
```
The `message_template` property supports [markdown](https://www.markdownguide.org). New lines needs to be escaped with `\n`.
### Miscellaneous topics
#### IPv6 support
Most of the [providers](#supported-dns-providers) support IPv6.
To enable the `IPv6` support of GoDNS, there are two solutions to choose from:
1. Use an online service to lookup the external IPv6
For that:
- Set the `ip_type` as `IPv6`, and make sure the `ipv6_url` is configured
- Create an `AAAA` record instead of an `A` record in your DNS provider
<details>
<summary>Configuration example</summary>
```json
{
"domains": [
{
"domain_name": "example.com",
"sub_domains": [
"ipv6"
]
}
],
"resolver": "2001:4860:4860::8888",
"ipv6_url": "https://api-ipv6.ip.sb/ip",
"ip_type": "IPv6"
}
```
</details>
2. Let GoDNS find the IPv6 of the network interface of the machine it is running on (more on that [later](#network-interface-ip-address)).
For this to happen, just leave `ip_url` and `ipv6_url` empty.
Note that the network interface must be configured with an IPv6 for this to work.
#### Network interface IP address
For some reasons if you want to get the IP address associated to a network interface (instead of performing an online lookup), you can specify it in the configuration file this way:
```json
...
"ip_url": "",
"ip_interface": "interface-name",
...
```
With `interface-name` replaced by the name of the network interface, e.g. `eth0` on Linux or `Local Area Connection` on Windows.
Note: If `ip_url` is also specified, it will be used to perform an online lookup first and the network interface IP will be used as a fallback in case of failure.
#### SOCKS5 proxy support
You can make all remote calls go through a [SOCKS5 proxy](https://en.wikipedia.org/wiki/SOCKS#SOCKS5) by specifying it in the configuration file this way:
```json
...
"socks5_proxy": "127.0.0.1:7070" "socks5_proxy": "127.0.0.1:7070"
"use_proxy": true
...
``` ```
## Running GoDNS Now all the queries will go through the specified SOCKS5 proxy.
There are few ways to run GoDNS. ## Run it as a daemon manually
### As a manual daemon
```bash ```bash
nohup ./godns & nohup ./godns &
``` ```
Note: when the program stops, it will not be restarted. ## Run it as a daemon, manage it via Upstart
### As a managed daemon (with upstart) * Install `upstart` first
* Copy `./upstart/godns.conf` to `/etc/init`
1. Install `upstart` first (if not available already) * Start it as a system service:
2. Copy `./upstart/godns.conf` to `/etc/init` (and tweak it to your needs)
3. Start the service:
```bash ```bash
sudo start godns sudo start godns
``` ```
### As a managed daemon (with systemd) ## Run it as a daemon, manage it via Systemd
1. Install `systemd` first (it not available already) * Modify `./systemd/godns.service` and config it.
2. Copy `./systemd/godns.service` to `/lib/systemd/system` (and tweak it to your needs) * Copy `./systemd/godns.service` to `/lib/systemd/system`
3. Start the service: * Start it as a systemd service:
```bash ```bash
sudo systemctl enable godns sudo systemctl enable godns
sudo systemctl start godns sudo systemctl start godns
``` ```
### As a Docker container ## Run it with docker
With `/path/to/config.json` your local configuration file, run: Now godns supports to run in docker.
* Get [config_sample.json](https://github.com/timothyye/godns/blob/master/config_sample.json) from Github.
* Rename it to **config.json**.
* Run GoDNS with docker:
```bash ```bash
docker run \ docker run -d --name godns --restart=always \
-d --name godns --restart=always \ -v /path/to/config.json:/usr/local/godns/config.json timothyye/godns:latest
-v /path/to/config.json:/config.json \
timothyye/godns:latest
``` ```
### As a Windows service ## Run it as a Windows service
1. Download the latest version of [NSSM](https://nssm.cc/download) * Get [birkett/srvany-ng](https://github.com/birkett/srvany-ng/releases) from Github.
* Uncompress and place the executable `srvany-ng.exe` to the same directory where `godns.exe` in.
* Create a service and add registry keys according to the guide [here](https://github.com/birkett/srvany-ng).
2. In an administrative prompt, from the folder where NSSM was downloaded, e.g. `C:\Downloads\nssm\` **win64**, run: ## Enjoy it!
```
nssm install YOURSERVICENAME
```
3. Follow the interface to configure the service. In the "Application" tab just indicate where the `godns.exe` file is. Optionally you can also define a description on the "Details" tab and define a log file on the "I/O" tab. Finish by clicking on the "Install service" button.
4. The service will now start along Windows.
Note: you can uninstall the service by running:
```
nssm remove YOURSERVICENAME
```
## Special Thanks
<img src="https://i.imgur.com/xhe5RLZ.jpg" width="80px" align="right" />
Thanks JetBrains for sponsoring this project with [free open source license](https://www.jetbrains.com/community/opensource/).
> I like GoLand, it is an amazing and productive tool.

View File

@ -1 +0,0 @@
theme: jekyll-theme-cayman

9
cmd/godns/Dockerfile Normal file
View File

@ -0,0 +1,9 @@
FROM timothyye/alpine:3.6-glibc
MAINTAINER Timothy
RUN apk add --update ca-certificates
RUN mkdir -p /usr/local/godns
COPY godns /usr/local/godns
RUN chmod +x /usr/local/godns/godns
RUN rm -rf /var/cache/apk/*
WORKDIR /usr/local/godns
ENTRYPOINT ["./godns", "-c", "/usr/local/godns/config.json"]

37
cmd/godns/Makefile Normal file
View File

@ -0,0 +1,37 @@
# Binary name
BINARY=godns
# Builds the project
build:
go build -o ${BINARY} -ldflags "-X main.Version=${VERSION}"
# Installs our project: copies binaries
install:
go install
release:
# Clean
go clean
rm -rf *.gz
# Build for mac
go build -o ${BINARY} -ldflags "-X main.Version=${VERSION}"
tar czvf ${BINARY}-mac64-${VERSION}.tar.gz ./${BINARY}
# Build for linux
go clean
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ${BINARY} -ldflags "-X main.Version=${VERSION}"
tar czvf ${BINARY}-linux64-${VERSION}.tar.gz ./${BINARY}
# Build for arm
go clean
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o ${BINARY} -ldflags "-X main.Version=${VERSION}"
tar czvf ${BINARY}-arm64-${VERSION}.tar.gz ./${BINARY}
go clean
CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -o ${BINARY} -ldflags "-X main.Version=${VERSION}"
tar czvf ${BINARY}-arm-${VERSION}.tar.gz ./${BINARY}
# Build for win
go clean
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o ${BINARY}.exe -ldflags "-X main.Version=${VERSION}"
tar czvf ${BINARY}-win64-${VERSION}.tar.gz ./${BINARY}.exe
go clean
# Cleans our projects: deletes binaries
clean:
go clean
rm -rf *.gz
.PHONY: clean build

View File

@ -41,7 +41,7 @@ func main() {
} }
// Init log settings // Init log settings
log.SetPrefix("[GoDNS] ") log.SetPrefix("【GoDNS】")
log.Println("GoDNS started, entering main loop...") log.Println("GoDNS started, entering main loop...")
dnsLoop() dnsLoop()
} }
@ -50,17 +50,17 @@ func dnsLoop() {
panicChan := make(chan godns.Domain) panicChan := make(chan godns.Domain)
log.Println("Creating DNS handler with provider:", configuration.Provider) log.Println("Creating DNS handler with provider:", configuration.Provider)
h := handler.CreateHandler(configuration.Provider) handler := handler.CreateHandler(configuration.Provider)
h.SetConfiguration(&configuration) handler.SetConfiguration(&configuration)
for i := range configuration.Domains { for i := range configuration.Domains {
go h.DomainLoop(&configuration.Domains[i], panicChan) go handler.DomainLoop(&configuration.Domains[i], panicChan)
} }
panicCount := 0 panicCount := 0
for { for {
failDomain := <-panicChan failDomain := <-panicChan
log.Println("Got panic in goroutine, will start a new one... :", panicCount) log.Println("Got panic in goroutine, will start a new one... :", panicCount)
go h.DomainLoop(&failDomain, panicChan) go handler.DomainLoop(&failDomain, panicChan)
panicCount++ panicCount++
if panicCount >= godns.PanicMax { if panicCount >= godns.PanicMax {

View File

@ -18,24 +18,10 @@
] ]
} }
], ],
"ip_url": "https://myip.biturl.top", "ip_url": "http://members.3322.org/dyndns/getip",
"ipv6_url": "https://api-ipv6.ip.sb/ip",
"ip_type": "IPv4",
"interval": 300,
"resolver": "8.8.8.8",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36",
"ip_interface": "eth0", "ip_interface": "eth0",
"socks5_proxy": "", "socks5_proxy": "",
"use_proxy": false,
"notify": { "notify": {
"telegram": {
"enabled": false,
"bot_api_key": "",
"chat_id": "",
"message_template": "",
"use_proxy": false
},
"mail": {
"enabled": false, "enabled": false,
"smtp_server": "", "smtp_server": "",
"smtp_username": "", "smtp_username": "",
@ -44,4 +30,3 @@
"send_to": "" "send_to": ""
} }
} }
}

18
go.mod
View File

@ -1,18 +0,0 @@
module github.com/TimothyYe/godns
require (
github.com/bitly/go-simplejson v0.5.0
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
github.com/bogdanovich/dns_resolver v0.0.0-20170211073258-a8e42bc6a5b6
github.com/fatih/color v1.7.0
github.com/google/uuid v1.1.1
github.com/kr/pretty v0.1.0 // indirect
github.com/mattn/go-colorable v0.0.9 // indirect
github.com/mattn/go-isatty v0.0.4 // indirect
github.com/miekg/dns v1.1.29
golang.org/x/net v0.0.0-20190923162816-aa69164e4478
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
)
go 1.13

46
go.sum
View File

@ -1,46 +0,0 @@
github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/bogdanovich/dns_resolver v0.0.0-20170211073258-a8e42bc6a5b6 h1:oV1V+uwP+sjmdSkvMxsl/l+HE+N8wbL49wCXZPel25M=
github.com/bogdanovich/dns_resolver v0.0.0-20170211073258-a8e42bc6a5b6/go.mod h1:txOV61Nn+21z77KUMkNsp8lTHoOFTtqotltQAFenS9I=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg=
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20190110200230-915654e7eabc h1:Yx9JGxI1SBhVLFjpAkWMaO1TF+xyqtHLjZpvQboJGiM=
golang.org/x/net v0.0.0-20190110200230-915654e7eabc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190226215855-775f8194d0f9 h1:N26gncmS+iqc/W/SKhX3ElI5pkt72XYoRLgi5Z70LSc=
golang.org/x/sys v0.0.0-20190226215855-775f8194d0f9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=

View File

@ -1,166 +0,0 @@
package alidns
import (
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"math/rand"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
"sync"
"time"
)
// AliDNS token
type AliDNS struct {
AccessKeyID string
AccessKeySecret string
}
var (
publicParm = map[string]string{
"AccessKeyId": "",
"Format": "JSON",
"Version": "2015-01-09",
"SignatureMethod": "HMAC-SHA1",
"Timestamp": "",
"SignatureVersion": "1.0",
"SignatureNonce": "",
}
baseURL = "http://alidns.aliyuncs.com/"
instance *AliDNS
once sync.Once
)
type domainRecordsResp struct {
RequestID string `json:"RequestId"`
TotalCount int
PageNumber int
PageSize int
DomainRecords domainRecords
}
type domainRecords struct {
Record []DomainRecord
}
// DomainRecord struct
type DomainRecord struct {
DomainName string
RecordID string `json:"RecordId"`
RR string
Type string
Value string
Line string
Priority int
TTL int
Status string
Locked bool
}
func getHTTPBody(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
body, err := ioutil.ReadAll(resp.Body)
if resp.StatusCode == http.StatusOK {
return body, err
}
return nil, fmt.Errorf("status %d, Error:%s", resp.StatusCode, body)
}
// NewAliDNS function creates instance of AliDNS and return
func NewAliDNS(key, secret string) *AliDNS {
once.Do(func() {
instance = &AliDNS{
AccessKeyID: key,
AccessKeySecret: secret,
}
})
return instance
}
// GetDomainRecords gets all the doamin records according to input subdomain key
func (d *AliDNS) GetDomainRecords(domain, rr string) []DomainRecord {
resp := &domainRecordsResp{}
parms := map[string]string{
"Action": "DescribeSubDomainRecords",
"SubDomain": fmt.Sprintf("%s.%s", rr, domain),
}
urlPath := d.genRequestURL(parms)
body, err := getHTTPBody(urlPath)
if err != nil {
fmt.Printf("GetDomainRecords error.%+v\n", err)
} else {
if err := json.Unmarshal(body, resp); err != nil {
fmt.Printf("GetDomainRecords error. %+v\n", err)
return nil
}
return resp.DomainRecords.Record
}
return nil
}
// UpdateDomainRecord updates domain record
func (d *AliDNS) UpdateDomainRecord(r DomainRecord) error {
parms := map[string]string{
"Action": "UpdateDomainRecord",
"RecordId": r.RecordID,
"RR": r.RR,
"Type": r.Type,
"Value": r.Value,
"TTL": strconv.Itoa(r.TTL),
"Line": r.Line,
}
urlPath := d.genRequestURL(parms)
if urlPath == "" {
return errors.New("failed to generate request URL")
}
_, err := getHTTPBody(urlPath)
if err != nil {
fmt.Printf("UpdateDomainRecord error.%+v\n", err)
}
return err
}
func (d *AliDNS) genRequestURL(parms map[string]string) string {
var pArr []string
ps := map[string]string{}
for k, v := range publicParm {
ps[k] = v
}
for k, v := range parms {
ps[k] = v
}
now := time.Now().UTC()
ps["AccessKeyId"] = d.AccessKeyID
ps["SignatureNonce"] = strconv.Itoa(int(now.UnixNano()) + rand.Intn(99999))
ps["Timestamp"] = now.Format("2006-01-02T15:04:05Z")
for k, v := range ps {
pArr = append(pArr, fmt.Sprintf("%s=%s", k, v))
}
sort.Strings(pArr)
path := strings.Join(pArr, "&")
s := "GET&%2F&" + url.QueryEscape(path)
s = strings.Replace(s, "%3A", "%253A", -1)
s = strings.Replace(s, "%40", "%2540", -1)
s = strings.Replace(s, "%2A", "%252A", -1)
mac := hmac.New(sha1.New, []byte(d.AccessKeySecret+"&"))
if _, err := mac.Write([]byte(s)); err != nil {
return ""
}
sign := base64.StdEncoding.EncodeToString(mac.Sum(nil))
return fmt.Sprintf("%s?%s&Signature=%s", baseURL, path, url.QueryEscape(sign))
}

View File

@ -1,85 +0,0 @@
package alidns
import (
"fmt"
"log"
"runtime/debug"
"time"
"github.com/TimothyYe/godns"
)
// Handler struct
type Handler struct {
Configuration *godns.Settings
}
// SetConfiguration pass dns settings and store it to handler instance
func (handler *Handler) SetConfiguration(conf *godns.Settings) {
handler.Configuration = conf
}
// DomainLoop the main logic loop
func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain) {
defer func() {
if err := recover(); err != nil {
log.Printf("Recovered in %v: %v\n", err, debug.Stack())
panicChan <- *domain
}
}()
looping := false
aliDNS := NewAliDNS(handler.Configuration.Email, handler.Configuration.Password)
for {
if looping {
// Sleep with interval
log.Printf("Going to sleep, will start next checking in %d seconds...\r\n", handler.Configuration.Interval)
time.Sleep(time.Second * time.Duration(handler.Configuration.Interval))
}
looping = true
currentIP, err := godns.GetCurrentIP(handler.Configuration)
if err != nil {
log.Println("Failed to get current IP:", err)
continue
}
log.Println("currentIP is:", currentIP)
for _, subDomain := range domain.SubDomains {
hostname := subDomain + "." + domain.DomainName
lastIP, err := godns.ResolveDNS(hostname, handler.Configuration.Resolver, handler.Configuration.IPType)
if err != nil {
log.Println(err)
continue
}
//check against currently known IP, if no change, skip update
if currentIP == lastIP {
log.Printf("IP is the same as cached one. Skip update.\n")
} else {
lastIP = currentIP
log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName)
records := aliDNS.GetDomainRecords(domain.DomainName, subDomain)
if records == nil || len(records) == 0 {
log.Printf("Cannot get subdomain %s from AliDNS.\r\n", subDomain)
continue
}
records[0].Value = currentIP
if err := aliDNS.UpdateDomainRecord(records[0]); err != nil {
log.Printf("Failed to update IP for subdomain:%s\r\n", subDomain)
continue
} else {
log.Printf("IP updated for subdomain:%s\r\n", subDomain)
}
// Send notification
if err := godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP); err != nil {
log.Printf("Failed to send notification")
}
}
}
}
}

View File

@ -1,22 +1,21 @@
package cloudflare package handler
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"log" "log"
"net/http" "net/http"
"runtime/debug" "runtime/debug"
"strings"
"time" "time"
"github.com/TimothyYe/godns" "github.com/TimothyYe/godns"
"golang.org/x/net/proxy"
) )
// Handler struct definition // CloudflareHandler struct definition
type Handler struct { type CloudflareHandler struct {
Configuration *godns.Settings Configuration *godns.Settings
API string API string
} }
@ -41,7 +40,6 @@ type DNSRecord struct {
Proxied bool `json:"proxied"` Proxied bool `json:"proxied"`
Type string `json:"type"` Type string `json:"type"`
ZoneID string `json:"zone_id"` ZoneID string `json:"zone_id"`
TTL int32 `json:"ttl"`
} }
// SetIP updates DNSRecord.IP // SetIP updates DNSRecord.IP
@ -62,13 +60,13 @@ type Zone struct {
} }
// SetConfiguration pass dns settings and store it to handler instance // SetConfiguration pass dns settings and store it to handler instance
func (handler *Handler) SetConfiguration(conf *godns.Settings) { func (handler *CloudflareHandler) SetConfiguration(conf *godns.Settings) {
handler.Configuration = conf handler.Configuration = conf
handler.API = "https://api.cloudflare.com/client/v4" handler.API = "https://api.cloudflare.com/client/v4"
} }
// DomainLoop the main logic loop // DomainLoop the main logic loop
func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain) { func (handler *CloudflareHandler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Printf("Recovered in %v: %v\n", err, debug.Stack()) log.Printf("Recovered in %v: %v\n", err, debug.Stack())
@ -77,15 +75,7 @@ func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.
}() }()
var lastIP string var lastIP string
looping := false
for { for {
if looping {
// Sleep with interval
log.Printf("Going to sleep, will start next checking in %d seconds...\r\n", handler.Configuration.Interval)
time.Sleep(time.Second * time.Duration(handler.Configuration.Interval))
}
looping = true
currentIP, err := godns.GetCurrentIP(handler.Configuration) currentIP, err := godns.GetCurrentIP(handler.Configuration)
if err != nil { if err != nil {
log.Println("Error in GetCurrentIP:", err) log.Println("Error in GetCurrentIP:", err)
@ -96,6 +86,8 @@ func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.
if currentIP == lastIP { if currentIP == lastIP {
log.Printf("IP is the same as cached one. Skip update.\n") log.Printf("IP is the same as cached one. Skip update.\n")
} else { } else {
lastIP = currentIP
log.Println("Checking IP for domain", domain.DomainName) log.Println("Checking IP for domain", domain.DomainName)
zoneID := handler.getZone(domain.DomainName) zoneID := handler.getZone(domain.DomainName)
if zoneID != "" { if zoneID != "" {
@ -103,18 +95,13 @@ func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.
// update records // update records
for _, rec := range records { for _, rec := range records {
if !recordTracked(domain, &rec) { if recordTracked(domain, &rec) != true {
log.Println("Skiping record:", rec.Name) log.Println("Skiping record:", rec.Name)
continue continue
} }
if rec.IP != currentIP { if rec.IP != currentIP {
log.Printf("IP mismatch: Current(%+v) vs Cloudflare(%+v)\r\n", currentIP, rec.IP) log.Printf("IP mismatch: Current(%+v) vs Cloudflare(%+v)\r\n", currentIP, rec.IP)
lastIP = handler.updateRecord(rec, currentIP) handler.updateRecord(rec, currentIP)
// Send notification
if err := godns.SendNotify(handler.Configuration, rec.Name, currentIP); err != nil {
log.Println("Failed to send notification")
}
} else { } else {
log.Printf("Record OK: %+v - %+v\r\n", rec.Name, rec.IP) log.Printf("Record OK: %+v - %+v\r\n", rec.Name, rec.IP)
} }
@ -123,16 +110,21 @@ func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.
log.Println("Failed to find zone for domain:", domain.DomainName) log.Println("Failed to find zone for domain:", domain.DomainName)
} }
} }
// Interval is 5 minutes
log.Printf("Going to sleep, will start next checking in %d minutes...\r\n", godns.INTERVAL)
time.Sleep(time.Minute * godns.INTERVAL)
} }
} }
// Check if record is present in domain conf // Check if record is present in domain conf
func recordTracked(domain *godns.Domain, record *DNSRecord) bool { func recordTracked(domain *godns.Domain, record *DNSRecord) bool {
if record.Name == domain.DomainName { if record.Name == domain.DomainName {
return true return true
} }
for _, subDomain := range domain.SubDomains { for _, subDomain := range domain.SubDomains {
sd := fmt.Sprintf("%s.%s", subDomain, domain.DomainName) sd := subDomain + "." + domain.DomainName
if record.Name == sd { if record.Name == sd {
return true return true
} }
@ -142,31 +134,34 @@ func recordTracked(domain *godns.Domain, record *DNSRecord) bool {
} }
// Create a new request with auth in place and optional proxy // Create a new request with auth in place and optional proxy
func (handler *Handler) newRequest(method, url string, body io.Reader) (*http.Request, *http.Client) { func (handler *CloudflareHandler) newRequest(method, url string, body io.Reader) (*http.Request, *http.Client) {
client := godns.GetHttpClient(handler.Configuration, handler.Configuration.UseProxy) client := &http.Client{}
if client == nil {
log.Println("cannot create HTTP client") if handler.Configuration.Socks5Proxy != "" {
log.Println("use socks5 proxy:" + handler.Configuration.Socks5Proxy)
dialer, err := proxy.SOCKS5("tcp", handler.Configuration.Socks5Proxy, nil, proxy.Direct)
if err != nil {
log.Println("can't connect to the proxy:", err)
} else {
httpTransport := &http.Transport{}
client.Transport = httpTransport
httpTransport.Dial = dialer.Dial
}
} }
req, _ := http.NewRequest(method, handler.API+url, body) req, _ := http.NewRequest(method, handler.API+url, body)
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
if handler.Configuration.Email != "" && handler.Configuration.Password != "" {
req.Header.Set("X-Auth-Email", handler.Configuration.Email) req.Header.Set("X-Auth-Email", handler.Configuration.Email)
req.Header.Set("X-Auth-Key", handler.Configuration.Password) req.Header.Set("X-Auth-Key", handler.Configuration.Password)
} else if handler.Configuration.LoginToken != "" {
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", handler.Configuration.LoginToken))
}
return req, client return req, client
} }
// Find the correct zone via domain name // Find the correct zone via domain name
func (handler *Handler) getZone(domain string) string { func (handler *CloudflareHandler) getZone(domain string) string {
var z ZoneResponse var z ZoneResponse
req, client := handler.newRequest("GET", fmt.Sprintf("/zones?name=%s", domain), nil) req, client := handler.newRequest("GET", "/zones", nil)
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
log.Println("Request error:", err.Error()) log.Println("Request error:", err.Error())
@ -194,20 +189,12 @@ func (handler *Handler) getZone(domain string) string {
} }
// Get all DNS A records for a zone // Get all DNS A records for a zone
func (handler *Handler) getDNSRecords(zoneID string) []DNSRecord { func (handler *CloudflareHandler) getDNSRecords(zoneID string) []DNSRecord {
var empty []DNSRecord var empty []DNSRecord
var r DNSRecordResponse var r DNSRecordResponse
var recordType string
if handler.Configuration.IPType == "" || strings.ToUpper(handler.Configuration.IPType) == godns.IPV4 { req, client := handler.newRequest("GET", "/zones/"+zoneID+"/dns_records?type=A", nil)
recordType = "A"
} else if strings.ToUpper(handler.Configuration.IPType) == godns.IPV6 {
recordType = "AAAA"
}
log.Println("Querying records with type:", recordType)
req, client := handler.newRequest("GET", fmt.Sprintf("/zones/"+zoneID+"/dns_records?type=%s&page=1&per_page=500", recordType), nil)
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
log.Println("Request error:", err.Error()) log.Println("Request error:", err.Error())
@ -231,11 +218,10 @@ func (handler *Handler) getDNSRecords(zoneID string) []DNSRecord {
} }
// Update DNS A Record with new IP // Update DNS A Record with new IP
func (handler *Handler) updateRecord(record DNSRecord, newIP string) string { func (handler *CloudflareHandler) updateRecord(record DNSRecord, newIP string) {
var r DNSRecordUpdateResponse var r DNSRecordUpdateResponse
record.SetIP(newIP) record.SetIP(newIP)
var lastIP string
j, _ := json.Marshal(record) j, _ := json.Marshal(record)
req, client := handler.newRequest("PUT", req, client := handler.newRequest("PUT",
@ -245,7 +231,7 @@ func (handler *Handler) updateRecord(record DNSRecord, newIP string) string {
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
log.Println("Request error:", err.Error()) log.Println("Request error:", err.Error())
return "" return
} }
body, _ := ioutil.ReadAll(resp.Body) body, _ := ioutil.ReadAll(resp.Body)
@ -253,14 +239,12 @@ func (handler *Handler) updateRecord(record DNSRecord, newIP string) string {
if err != nil { if err != nil {
log.Printf("Decoder error: %+v\n", err) log.Printf("Decoder error: %+v\n", err)
log.Printf("Response body: %+v\n", string(body)) log.Printf("Response body: %+v\n", string(body))
return "" return
} }
if r.Success != true { if r.Success != true {
body, _ := ioutil.ReadAll(resp.Body) body, _ := ioutil.ReadAll(resp.Body)
log.Printf("Response failed: %+v\n", string(body)) log.Printf("Response failed: %+v\n", string(body))
} else { } else {
log.Printf("Record updated: %+v - %+v", record.Name, record.IP) log.Printf("Record updated: %+v - %+v", record.Name, record.IP)
lastIP = record.IP
} }
return lastIP
} }

View File

@ -1,4 +1,4 @@
package cloudflare package handler
import ( import (
"encoding/json" "encoding/json"
@ -160,8 +160,8 @@ func TestRecordTracked(t *testing.T) {
} }
for _, rec := range resp.Records { for _, rec := range resp.Records {
if recordTracked(domain, &rec) { if recordTracked(domain, &rec) != true {
t.Logf("Record founded: %+v\r\n", rec.Name) t.Errorf("invalid record skip: %+v\r\n", rec.Name)
} }
} }
} }

View File

@ -1,8 +1,7 @@
package dnspod package handler
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
@ -15,20 +14,21 @@ import (
"github.com/TimothyYe/godns" "github.com/TimothyYe/godns"
"github.com/bitly/go-simplejson" "github.com/bitly/go-simplejson"
"golang.org/x/net/proxy"
) )
// Handler struct definition // DNSPodHandler struct definition
type Handler struct { type DNSPodHandler struct {
Configuration *godns.Settings Configuration *godns.Settings
} }
// SetConfiguration pass dns settings and store it to handler instance // SetConfiguration pass dns settings and store it to handler instance
func (handler *Handler) SetConfiguration(conf *godns.Settings) { func (handler *DNSPodHandler) SetConfiguration(conf *godns.Settings) {
handler.Configuration = conf handler.Configuration = conf
} }
// DomainLoop the main logic loop // DomainLoop the main logic loop
func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain) { func (handler *DNSPodHandler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Printf("Recovered in %v: %v\n", err, debug.Stack()) log.Printf("Recovered in %v: %v\n", err, debug.Stack())
@ -36,16 +36,8 @@ func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.
} }
}() }()
looping := false var lastIP string
for { for {
if looping {
// Sleep with interval
log.Printf("Going to sleep, will start next checking in %d seconds...\r\n", handler.Configuration.Interval)
time.Sleep(time.Second * time.Duration(handler.Configuration.Interval))
}
looping = true
log.Printf("Checking IP for domain %s \r\n", domain.DomainName) log.Printf("Checking IP for domain %s \r\n", domain.DomainName)
domainID := handler.GetDomain(domain.DomainName) domainID := handler.GetDomain(domain.DomainName)
@ -61,46 +53,45 @@ func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.
} }
log.Println("currentIP is:", currentIP) log.Println("currentIP is:", currentIP)
for _, subDomain := range domain.SubDomains { //check against locally cached IP, if no change, skip update
hostname := subDomain + "." + domain.DomainName
lastIP, err := godns.ResolveDNS(hostname, handler.Configuration.Resolver, handler.Configuration.IPType)
if err != nil {
log.Println(err)
continue
}
//check against currently known IP, if no change, skip update
if currentIP == lastIP { if currentIP == lastIP {
log.Printf("IP is the same as cached one. Skip update.\n") log.Printf("IP is the same as cached one. Skip update.\n")
} else { } else {
lastIP = currentIP lastIP = currentIP
for _, subDomain := range domain.SubDomains {
subDomainID, ip := handler.GetSubDomain(domainID, subDomain) subDomainID, ip := handler.GetSubDomain(domainID, subDomain)
if subDomainID == "" || ip == "" { if subDomainID == "" || ip == "" {
log.Printf("Domain or subdomain not configured yet. domain: %s.%s subDomainID: %s ip: %s\n", subDomain, domain.DomainName, subDomainID, ip) log.Printf("domain: %s.%s subDomainID: %s ip: %s\n", subDomain, domain.DomainName, subDomainID, ip)
continue continue
} }
// Continue to check the IP of subdomain // Continue to check the IP of sub-domain
if len(ip) > 0 && strings.TrimRight(currentIP, "\n") != strings.TrimRight(ip, "\n") { if len(ip) > 0 && strings.TrimRight(currentIP, "\n") != strings.TrimRight(ip, "\n") {
log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName)
handler.UpdateIP(domainID, subDomainID, subDomain, currentIP) handler.UpdateIP(domainID, subDomainID, subDomain, currentIP)
// Send notification // Send mail notification if notify is enabled
if err := godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP); err != nil { if handler.Configuration.Notify.Enabled {
log.Println("Failed to send notification") log.Print("Sending notification to:", handler.Configuration.Notify.SendTo)
godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP)
} }
} else { } else {
log.Printf("%s.%s Current IP is same as domain IP, no need to update...\n", subDomain, domain.DomainName) log.Printf("%s.%s Current IP is same as domain IP, no need to update...\n", subDomain, domain.DomainName)
} }
} }
} }
// Interval is 5 minutes
log.Printf("Going to sleep, will start next checking in %d minutes...\r\n", godns.INTERVAL)
time.Sleep(time.Minute * godns.INTERVAL)
} }
} }
// GenerateHeader generates the request header for DNSPod API // GenerateHeader generates the request header for DNSPod API
func (handler *Handler) GenerateHeader(content url.Values) url.Values { func (handler *DNSPodHandler) GenerateHeader(content url.Values) url.Values {
header := url.Values{} header := url.Values{}
if handler.Configuration.LoginToken != "" { if handler.Configuration.LoginToken != "" {
header.Add("login_token", handler.Configuration.LoginToken) header.Add("login_token", handler.Configuration.LoginToken)
@ -120,7 +111,7 @@ func (handler *Handler) GenerateHeader(content url.Values) url.Values {
} }
// GetDomain returns specific domain by name // GetDomain returns specific domain by name
func (handler *Handler) GetDomain(name string) int64 { func (handler *DNSPodHandler) GetDomain(name string) int64 {
var ret int64 var ret int64
values := url.Values{} values := url.Values{}
@ -169,7 +160,8 @@ func (handler *Handler) GetDomain(name string) int64 {
} }
// GetSubDomain returns subdomain by domain id // GetSubDomain returns subdomain by domain id
func (handler *Handler) GetSubDomain(domainID int64, name string) (string, string) { func (handler *DNSPodHandler) GetSubDomain(domainID int64, name string) (string, string) {
log.Println("debug:", domainID, name)
var ret, ip string var ret, ip string
value := url.Values{} value := url.Values{}
value.Add("domain_id", strconv.FormatInt(domainID, 10)) value.Add("domain_id", strconv.FormatInt(domainID, 10))
@ -177,15 +169,6 @@ func (handler *Handler) GetSubDomain(domainID int64, name string) (string, strin
value.Add("length", "1") value.Add("length", "1")
value.Add("sub_domain", name) value.Add("sub_domain", name)
if handler.Configuration.IPType == "" || strings.ToUpper(handler.Configuration.IPType) == godns.IPV4 {
value.Add("record_type", "A")
} else if strings.ToUpper(handler.Configuration.IPType) == godns.IPV6 {
value.Add("record_type", "AAAA")
} else {
log.Println("Error: must specify \"ip_type\" in config for DNSPod.")
return "", ""
}
response, err := handler.PostData("/Record.List", value) response, err := handler.PostData("/Record.List", value)
if err != nil { if err != nil {
@ -222,21 +205,12 @@ func (handler *Handler) GetSubDomain(domainID int64, name string) (string, strin
} }
// UpdateIP update subdomain with current IP // UpdateIP update subdomain with current IP
func (handler *Handler) UpdateIP(domainID int64, subDomainID string, subDomainName string, ip string) { func (handler *DNSPodHandler) UpdateIP(domainID int64, subDomainID string, subDomainName string, ip string) {
value := url.Values{} value := url.Values{}
value.Add("domain_id", strconv.FormatInt(domainID, 10)) value.Add("domain_id", strconv.FormatInt(domainID, 10))
value.Add("record_id", subDomainID) value.Add("record_id", subDomainID)
value.Add("sub_domain", subDomainName) value.Add("sub_domain", subDomainName)
if strings.ToUpper(handler.Configuration.IPType) == godns.IPV4 {
value.Add("record_type", "A") value.Add("record_type", "A")
} else if strings.ToUpper(handler.Configuration.IPType) == godns.IPV6 {
value.Add("record_type", "AAAA")
} else {
log.Println("Error: must specify \"ip_type\" in config for DNSPod.")
return
}
value.Add("record_line", "默认") value.Add("record_line", "默认")
value.Add("value", ip) value.Add("value", ip)
@ -257,18 +231,27 @@ func (handler *Handler) UpdateIP(domainID int64, subDomainID string, subDomainNa
if sjson.Get("status").Get("code").MustString() == "1" { if sjson.Get("status").Get("code").MustString() == "1" {
log.Println("New IP updated!") log.Println("New IP updated!")
} else {
log.Println("Failed to update IP record:", sjson.Get("status").Get("message").MustString())
} }
} }
// PostData post data and invoke DNSPod API // PostData post data and invoke DNSPod API
func (handler *Handler) PostData(url string, content url.Values) (string, error) { func (handler *DNSPodHandler) PostData(url string, content url.Values) (string, error) {
client := godns.GetHttpClient(handler.Configuration, handler.Configuration.UseProxy) client := &http.Client{}
if client == nil { if handler.Configuration.Socks5Proxy != "" {
return "", errors.New("failed to create HTTP client")
log.Println("use socks5 proxy:" + handler.Configuration.Socks5Proxy)
dialer, err := proxy.SOCKS5("tcp", handler.Configuration.Socks5Proxy, nil, proxy.Direct)
if err != nil {
fmt.Println("can't connect to the proxy:", err)
return "", err
}
httpTransport := &http.Transport{}
client.Transport = httpTransport
httpTransport.Dial = dialer.Dial
} }
values := handler.GenerateHeader(content) values := handler.GenerateHeader(content)

View File

@ -1,138 +0,0 @@
package dreamhost
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"runtime/debug"
"strings"
"time"
"github.com/TimothyYe/godns"
"github.com/google/uuid"
)
var (
// DreamhostURL the API address for dreamhost.com
DreamhostURL = "https://api.dreamhost.com"
)
// Handler struct
type Handler struct {
Configuration *godns.Settings
}
// SetConfiguration pass dns settings and store it to handler instance
func (handler *Handler) SetConfiguration(conf *godns.Settings) {
handler.Configuration = conf
}
// DomainLoop the main logic loop
func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain) {
defer func() {
if err := recover(); err != nil {
log.Printf("Recovered in %v: %v\n", err, debug.Stack())
panicChan <- *domain
}
}()
looping := false
for {
if looping {
// Sleep with interval
log.Printf("Going to sleep, will start next checking in %d seconds...\r\n", handler.Configuration.Interval)
time.Sleep(time.Second * time.Duration(handler.Configuration.Interval))
}
looping = true
currentIP, err := godns.GetCurrentIP(handler.Configuration)
if err != nil {
log.Println("get_currentIP:", err)
continue
}
log.Println("currentIP is:", currentIP)
for _, subDomain := range domain.SubDomains {
hostname := subDomain + "." + domain.DomainName
lastIP, err := godns.ResolveDNS(hostname, handler.Configuration.Resolver, handler.Configuration.IPType)
if err != nil {
log.Println(err)
continue
}
//check against currently known IP, if no change, skip update
if currentIP == lastIP {
log.Printf("IP is the same as cached one. Skip update.\n")
} else {
log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName)
handler.UpdateIP(hostname, currentIP, lastIP)
// Send notification
if err := godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP); err != nil {
log.Println("Failed to send notification")
}
}
}
}
}
// UpdateIP update subdomain with current IP
func (handler *Handler) UpdateIP(hostname, currentIP, lastIP string) {
handler.updateDNS(lastIP, currentIP, hostname, "remove")
handler.updateDNS(lastIP, currentIP, hostname, "add")
}
// updateDNS can add or remove DNS records.
func (handler *Handler) updateDNS(dns, ip, hostname, action string) {
ipType := "A"
if strings.ToUpper(handler.Configuration.IPType) == godns.IPV6 {
ipType = "AAAA"
}
// Generates UUID
uid, _ := uuid.NewRandom()
values := url.Values{}
values.Add("record", hostname)
values.Add("key", handler.Configuration.LoginToken)
values.Add("type", ipType)
values.Add("unique_id", uid.String())
switch action {
case "remove":
// Build URL query (remove)
values.Add("cmd", "dns-remove_record")
values.Add("value", dns)
case "add":
// Build URL query (add)
values.Add("cmd", "dns-add_record")
values.Add("value", ip)
default:
log.Fatalf("Unknown action %s\n", action)
}
client := godns.GetHttpClient(handler.Configuration, handler.Configuration.UseProxy)
req, _ := http.NewRequest("POST", DreamhostURL, strings.NewReader(values.Encode()))
req.SetBasicAuth(handler.Configuration.Email, handler.Configuration.Password)
if handler.Configuration.UserAgent != "" {
req.Header.Add("User-Agent", handler.Configuration.UserAgent)
}
resp, err := client.Do(req)
if err != nil {
log.Println("Request error...")
log.Println("Err:", err.Error())
} else {
body, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode == http.StatusOK {
log.Println("Update IP success:", string(body))
} else {
log.Println("Update IP failed:", string(body))
}
}
}

View File

@ -1,102 +0,0 @@
package duck
import (
"fmt"
"io/ioutil"
"log"
"runtime/debug"
"strings"
"time"
"github.com/TimothyYe/godns"
)
var (
// DuckUrl the API address for Duck DNS
DuckUrl = "https://www.duckdns.org/update?domains=%s&token=%s&%s"
)
// Handler struct
type Handler struct {
Configuration *godns.Settings
}
// SetConfiguration pass dns settings and store it to handler instance
func (handler *Handler) SetConfiguration(conf *godns.Settings) {
handler.Configuration = conf
}
// DomainLoop the main logic loop
func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain) {
defer func() {
if err := recover(); err != nil {
log.Printf("Recovered in %v: %v\n", err, debug.Stack())
panicChan <- *domain
}
}()
looping := false
for {
if looping {
// Sleep with interval
log.Printf("Going to sleep, will start next checking in %d seconds...\r\n", handler.Configuration.Interval)
time.Sleep(time.Second * time.Duration(handler.Configuration.Interval))
}
looping = true
currentIP, err := godns.GetCurrentIP(handler.Configuration)
if err != nil {
log.Println("get_currentIP:", err)
continue
}
log.Println("currentIP is:", currentIP)
client := godns.GetHttpClient(handler.Configuration, handler.Configuration.UseProxy)
var ip string
if strings.ToUpper(handler.Configuration.IPType) == godns.IPV4 {
ip = fmt.Sprintf("ip=%s", currentIP)
} else if strings.ToUpper(handler.Configuration.IPType) == godns.IPV6 {
ip = fmt.Sprintf("ipv6=%s", currentIP)
}
for _, subDomain := range domain.SubDomains {
hostname := subDomain + "." + domain.DomainName
lastIP, err := godns.ResolveDNS(hostname, handler.Configuration.Resolver, handler.Configuration.IPType)
if err != nil {
log.Println(err)
continue
}
//check against currently known IP, if no change, skip update
if currentIP == lastIP {
log.Printf("IP is the same as cached one. Skip update.\n")
} else {
// update IP with HTTP GET request
resp, err := client.Get(fmt.Sprintf(DuckUrl, subDomain, handler.Configuration.LoginToken, ip))
if err != nil {
// handle error
log.Print("Failed to update sub domain:", subDomain)
continue
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil || string(body) != "OK" {
log.Println("Failed to update the IP")
continue
} else {
log.Print("IP updated to:", currentIP)
}
// Send notification
if err := godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP); err != nil {
log.Println("Failed to send notification")
}
}
}
}
}

View File

@ -1,113 +0,0 @@
package google
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"runtime/debug"
"strings"
"time"
"github.com/TimothyYe/godns"
)
var (
// GoogleURL the API address for Google Domains
GoogleURL = "https://%s:%s@domains.google.com/nic/update?hostname=%s.%s&myip=%s"
)
// Handler struct
type Handler struct {
Configuration *godns.Settings
}
// SetConfiguration pass dns settings and store it to handler instance
func (handler *Handler) SetConfiguration(conf *godns.Settings) {
handler.Configuration = conf
}
// DomainLoop the main logic loop
func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain) {
defer func() {
if err := recover(); err != nil {
log.Printf("Recovered in %v: %v\n", err, debug.Stack())
panicChan <- *domain
}
}()
looping := false
for {
if looping {
// Sleep with interval
log.Printf("Going to sleep, will start next checking in %d seconds...\r\n", handler.Configuration.Interval)
time.Sleep(time.Second * time.Duration(handler.Configuration.Interval))
}
looping = true
currentIP, err := godns.GetCurrentIP(handler.Configuration)
if err != nil {
log.Println("get_currentIP:", err)
continue
}
log.Println("currentIP is:", currentIP)
for _, subDomain := range domain.SubDomains {
hostname := subDomain + "." + domain.DomainName
lastIP, err := godns.ResolveDNS(hostname, handler.Configuration.Resolver, handler.Configuration.IPType)
if err != nil {
log.Println(err)
continue
}
//check against currently known IP, if no change, skip update
if currentIP == lastIP {
log.Printf("IP is the same as cached one. Skip update.\n")
} else {
log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName)
handler.UpdateIP(domain.DomainName, subDomain, currentIP)
// Send notification
if err := godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP); err != nil {
log.Println("Failed to send notification")
}
}
}
}
}
// UpdateIP update subdomain with current IP
func (handler *Handler) UpdateIP(domain, subDomain, currentIP string) {
client := godns.GetHttpClient(handler.Configuration, handler.Configuration.UseProxy)
resp, err := client.Get(fmt.Sprintf(GoogleURL,
handler.Configuration.Email,
handler.Configuration.Password,
subDomain,
domain,
currentIP))
if err != nil {
// handle error
log.Print("Failed to update sub domain:", subDomain)
return
}
defer resp.Body.Close()
if err != nil {
log.Println("Request error...")
log.Println("Err:", err.Error())
} else {
body, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode == http.StatusOK {
if strings.Contains(string(body), "good") {
log.Println("Update IP success:", string(body))
} else if strings.Contains(string(body), "nochg") {
log.Println("IP not changed:", string(body))
}
} else {
log.Println("Update IP failed:", string(body))
}
}
}

View File

@ -1,16 +1,6 @@
package handler package handler
import ( import "github.com/TimothyYe/godns"
"github.com/TimothyYe/godns"
"github.com/TimothyYe/godns/handler/alidns"
"github.com/TimothyYe/godns/handler/cloudflare"
"github.com/TimothyYe/godns/handler/dnspod"
"github.com/TimothyYe/godns/handler/dreamhost"
"github.com/TimothyYe/godns/handler/duck"
"github.com/TimothyYe/godns/handler/google"
"github.com/TimothyYe/godns/handler/he"
"github.com/TimothyYe/godns/handler/noip"
)
// IHandler is the interface for all DNS handlers // IHandler is the interface for all DNS handlers
type IHandler interface { type IHandler interface {
@ -18,27 +8,17 @@ type IHandler interface {
DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain) DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain)
} }
// CreateHandler creates DNS handler by different providers // CreateHandler creates dns handler by different providers
func CreateHandler(provider string) IHandler { func CreateHandler(provider string) IHandler {
var handler IHandler var handler IHandler
switch provider { switch provider {
case godns.CLOUDFLARE: case godns.CLOUDFLARE:
handler = IHandler(&cloudflare.Handler{}) handler = IHandler(&CloudflareHandler{})
case godns.DNSPOD: case godns.DNSPOD:
handler = IHandler(&dnspod.Handler{}) handler = IHandler(&DNSPodHandler{})
case godns.DREAMHOST:
handler = IHandler(&dreamhost.Handler{})
case godns.HE: case godns.HE:
handler = IHandler(&he.Handler{}) handler = IHandler(&HEHandler{})
case godns.ALIDNS:
handler = IHandler(&alidns.Handler{})
case godns.GOOGLE:
handler = IHandler(&google.Handler{})
case godns.DUCK:
handler = IHandler(&duck.Handler{})
case godns.NOIP:
handler = IHandler(&noip.Handler{})
} }
return handler return handler

View File

@ -1,4 +1,4 @@
package he package handler
import ( import (
"fmt" "fmt"
@ -11,6 +11,8 @@ import (
"time" "time"
"github.com/TimothyYe/godns" "github.com/TimothyYe/godns"
"golang.org/x/net/proxy"
) )
var ( var (
@ -18,18 +20,18 @@ var (
HEUrl = "https://dyn.dns.he.net/nic/update" HEUrl = "https://dyn.dns.he.net/nic/update"
) )
// Handler struct // HEHandler struct
type Handler struct { type HEHandler struct {
Configuration *godns.Settings Configuration *godns.Settings
} }
// SetConfiguration pass dns settings and store it to handler instance // SetConfiguration pass dns settings and store it to handler instance
func (handler *Handler) SetConfiguration(conf *godns.Settings) { func (handler *HEHandler) SetConfiguration(conf *godns.Settings) {
handler.Configuration = conf handler.Configuration = conf
} }
// DomainLoop the main logic loop // DomainLoop the main logic loop
func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain) { func (handler *HEHandler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Printf("Recovered in %v: %v\n", err, debug.Stack()) log.Printf("Recovered in %v: %v\n", err, debug.Stack())
@ -37,15 +39,8 @@ func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.
} }
}() }()
looping := false var lastIP string
for { for {
if looping {
// Sleep with interval
log.Printf("Going to sleep, will start next checking in %d seconds...\r\n", handler.Configuration.Interval)
time.Sleep(time.Second * time.Duration(handler.Configuration.Interval))
}
looping = true
currentIP, err := godns.GetCurrentIP(handler.Configuration) currentIP, err := godns.GetCurrentIP(handler.Configuration)
if err != nil { if err != nil {
@ -55,40 +50,50 @@ func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.
log.Println("currentIP is:", currentIP) log.Println("currentIP is:", currentIP)
//check against locally cached IP, if no change, skip update //check against locally cached IP, if no change, skip update
for _, subDomain := range domain.SubDomains {
hostname := subDomain + "." + domain.DomainName
lastIP, err := godns.ResolveDNS(hostname, handler.Configuration.Resolver, handler.Configuration.IPType)
if err != nil {
log.Println(err)
continue
}
//check against currently known IP, if no change, skip update
if currentIP == lastIP { if currentIP == lastIP {
log.Printf("IP is the same as cached one. Skip update.\n") log.Printf("IP is the same as cached one. Skip update.\n")
} else { } else {
lastIP = currentIP
for _, subDomain := range domain.SubDomains {
log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName)
handler.UpdateIP(domain.DomainName, subDomain, currentIP) handler.UpdateIP(domain.DomainName, subDomain, currentIP)
// Send notification // Send mail notification if notify is enabled
if err := godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP); err != nil { if handler.Configuration.Notify.Enabled {
log.Println("Failed to send notification") log.Print("Sending notification to:", handler.Configuration.Notify.SendTo)
godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP)
} }
} }
} }
// Interval is 5 minutes
log.Printf("Going to sleep, will start next checking in %d minutes...\r\n", godns.INTERVAL)
time.Sleep(time.Minute * godns.INTERVAL)
} }
} }
// UpdateIP update subdomain with current IP // UpdateIP update subdomain with current IP
func (handler *Handler) UpdateIP(domain, subDomain, currentIP string) { func (handler *HEHandler) UpdateIP(domain, subDomain, currentIP string) {
values := url.Values{} values := url.Values{}
values.Add("hostname", fmt.Sprintf("%s.%s", subDomain, domain)) values.Add("hostname", fmt.Sprintf("%s.%s", subDomain, domain))
values.Add("password", handler.Configuration.Password) values.Add("password", handler.Configuration.Password)
values.Add("myip", currentIP) values.Add("myip", currentIP)
client := godns.GetHttpClient(handler.Configuration, handler.Configuration.UseProxy) client := &http.Client{}
if handler.Configuration.Socks5Proxy != "" {
log.Println("use socks5 proxy:" + handler.Configuration.Socks5Proxy)
dialer, err := proxy.SOCKS5("tcp", handler.Configuration.Socks5Proxy, nil, proxy.Direct)
if err != nil {
log.Println("can't connect to the proxy:", err)
return
}
httpTransport := &http.Transport{}
client.Transport = httpTransport
httpTransport.Dial = dialer.Dial
}
req, _ := http.NewRequest("POST", HEUrl, strings.NewReader(values.Encode())) req, _ := http.NewRequest("POST", HEUrl, strings.NewReader(values.Encode()))
resp, err := client.Do(req) resp, err := client.Do(req)

View File

@ -1,114 +0,0 @@
package noip
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"runtime/debug"
"strings"
"time"
"github.com/TimothyYe/godns"
)
var (
// NoIPUrl the API address for NoIP
NoIPUrl = "https://%s:%s@dynupdate.no-ip.com/nic/update?hostname=%s&%s"
)
// Handler struct
type Handler struct {
Configuration *godns.Settings
}
// SetConfiguration pass dns settings and store it to handler instance
func (handler *Handler) SetConfiguration(conf *godns.Settings) {
handler.Configuration = conf
}
// DomainLoop the main logic loop
func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain) {
defer func() {
if err := recover(); err != nil {
log.Printf("Recovered in %v: %v\n", err, debug.Stack())
panicChan <- *domain
}
}()
looping := false
for {
if looping {
// Sleep with interval
log.Printf("Going to sleep, will start next checking in %d seconds...\r\n", handler.Configuration.Interval)
time.Sleep(time.Second * time.Duration(handler.Configuration.Interval))
}
looping = true
currentIP, err := godns.GetCurrentIP(handler.Configuration)
if err != nil {
log.Println("get_currentIP:", err)
continue
}
log.Println("currentIP is:", currentIP)
client := godns.GetHttpClient(handler.Configuration, handler.Configuration.UseProxy)
var ip string
if strings.ToUpper(handler.Configuration.IPType) == godns.IPV4 {
ip = fmt.Sprintf("myip=%s", currentIP)
} else if strings.ToUpper(handler.Configuration.IPType) == godns.IPV6 {
ip = fmt.Sprintf("myipv6=%s", currentIP)
}
for _, subDomain := range domain.SubDomains {
hostname := subDomain + "." + domain.DomainName
lastIP, err := godns.ResolveDNS(hostname, handler.Configuration.Resolver, handler.Configuration.IPType)
if err != nil {
log.Println(err)
continue
}
//check against currently known IP, if no change, skip update
if currentIP == lastIP {
log.Printf("IP is the same as cached one. Skip update.\n")
} else {
req, _ := http.NewRequest("GET", fmt.Sprintf(
NoIPUrl,
handler.Configuration.Email,
handler.Configuration.Password,
hostname,
ip), nil)
if handler.Configuration.UserAgent != "" {
req.Header.Add("User-Agent", handler.Configuration.UserAgent)
}
// update IP with HTTP GET request
resp, err := client.Do(req)
if err != nil {
// handle error
log.Print("Failed to update sub domain:", subDomain)
continue
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil || !strings.Contains(string(body), "good") {
log.Println("Failed to update the IP")
continue
} else {
log.Print("IP updated to:", currentIP)
}
// Send notification
if err := godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP); err != nil {
log.Println("Failed to send notification")
}
}
}
}
}

View File

@ -1,110 +0,0 @@
// Package resolver is a simple dns resolver
// based on miekg/dns
package resolver
import (
"errors"
"math/rand"
"net"
"os"
"strings"
"time"
"github.com/miekg/dns"
)
// DNSResolver represents a dns resolver
type DNSResolver struct {
Servers []string
RetryTimes int
r *rand.Rand
}
// New initializes DnsResolver.
func New(servers []string) *DNSResolver {
for i := range servers {
servers[i] = net.JoinHostPort(servers[i], "53")
}
return &DNSResolver{servers, len(servers) * 2, rand.New(rand.NewSource(time.Now().UnixNano()))}
}
// NewFromResolvConf initializes DnsResolver from resolv.conf like file.
func NewFromResolvConf(path string) (*DNSResolver, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
return &DNSResolver{}, errors.New("no such file or directory: " + path)
}
config, err := dns.ClientConfigFromFile(path)
if err != nil {
return &DNSResolver{}, err
}
var servers []string
for _, ipAddress := range config.Servers {
servers = append(servers, net.JoinHostPort(ipAddress, "53"))
}
return &DNSResolver{servers, len(servers) * 2, rand.New(rand.NewSource(time.Now().UnixNano()))}, err
}
// LookupHost returns IP addresses of provied host.
// In case of timeout retries query RetryTimes times.
func (r *DNSResolver) LookupHost(host string, dnsType uint16) ([]net.IP, error) {
return r.lookupHost(host, dnsType, r.RetryTimes)
}
func (r *DNSResolver) lookupHost(host string, dnsType uint16, triesLeft int) ([]net.IP, error) {
m1 := new(dns.Msg)
m1.Id = dns.Id()
m1.RecursionDesired = true
m1.Question = make([]dns.Question, 1)
switch dnsType {
case dns.TypeA:
m1.Question[0] = dns.Question{Name: dns.Fqdn(host), Qtype: dns.TypeA, Qclass: dns.ClassINET}
case dns.TypeAAAA:
m1.Question[0] = dns.Question{Name: dns.Fqdn(host), Qtype: dns.TypeAAAA, Qclass: dns.ClassINET}
}
in, err := dns.Exchange(m1, r.Servers[r.r.Intn(len(r.Servers))])
var result []net.IP
if err != nil {
if strings.HasSuffix(err.Error(), "i/o timeout") && triesLeft > 0 {
triesLeft--
return r.lookupHost(host, dnsType, triesLeft)
}
return result, err
}
if in != nil && in.Rcode != dns.RcodeSuccess {
return result, errors.New(dns.RcodeToString[in.Rcode])
}
if dnsType == dns.TypeA {
if len(in.Answer) > 0 {
for _, record := range in.Answer {
if t, ok := record.(*dns.A); ok {
result = append(result, t.A)
}
}
} else {
return result, errors.New("empty result")
}
}
if dnsType == dns.TypeAAAA {
if len(in.Answer) > 0 {
for _, record := range in.Answer {
if t, ok := record.(*dns.AAAA); ok {
result = append(result, t.AAAA)
}
}
} else {
return result, errors.New("Cannot resolve this domain, please make sure the IP type is right")
}
}
return result, err
}

View File

@ -1,45 +0,0 @@
package resolver
import (
"fmt"
"reflect"
"testing"
"github.com/miekg/dns"
)
func TestNew(t *testing.T) {
servers := []string{"8.8.8.8", "8.8.4.4"}
expectedServers := []string{"8.8.8.8:53", "8.8.4.4:53"}
resolver := New(servers)
if !reflect.DeepEqual(resolver.Servers, expectedServers) {
t.Error("resolver.Servers: ", resolver.Servers, "should be equal to", expectedServers)
}
}
func TestLookupHost_ValidServer(t *testing.T) {
resolver := New([]string{"8.8.8.8", "8.8.4.4"})
result, err := resolver.LookupHost("google-public-dns-a.google.com", dns.TypeA)
if err != nil {
fmt.Println(err.Error())
t.Error("Should succeed dns lookup")
}
if result[0].String() != "8.8.8.8" {
t.Error("google-public-dns-a.google.com should be resolved to 8.8.8.8")
}
}
func TestLookupHostIPv6_ValidServer(t *testing.T) {
resolver := New([]string{"2001:4860:4860::8888", "2001:4860:4860::8844"})
result, err := resolver.LookupHost("google-public-dns-a.google.com", dns.TypeAAAA)
if err != nil {
fmt.Println(err.Error())
t.Error("Should succeed dns lookup")
}
if result[0].String() != "2001:4860:4860::8888" {
t.Error("result should be: 2001:4860:4860::8888")
}
}

View File

@ -12,26 +12,8 @@ type Domain struct {
SubDomains []string `json:"sub_domains"` SubDomains []string `json:"sub_domains"`
} }
// Notify struct for slack notification
type SlackNotify struct {
Enabled bool `json:"enabled"`
BotApiToken string `json:"bot_api_token"`
Channel string `json:"channel"`
MsgTemplate string `json:"message_template"`
UseProxy bool `json:"use_proxy"`
}
// Notify struct for telegram notification
type TelegramNotify struct {
Enabled bool `json:"enabled"`
BotApiKey string `json:"bot_api_key"`
ChatId string `json:"chat_id"`
MsgTemplate string `json:"message_template"`
UseProxy bool `json:"use_proxy"`
}
// Notify struct for SMTP notification // Notify struct for SMTP notification
type MailNotify struct { type Notify struct {
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
SMTPServer string `json:"smtp_server"` SMTPServer string `json:"smtp_server"`
SMTPUsername string `json:"smtp_username"` SMTPUsername string `json:"smtp_username"`
@ -40,13 +22,6 @@ type MailNotify struct {
SendTo string `json:"send_to"` SendTo string `json:"send_to"`
} }
// Notify struct
type Notify struct {
Telegram TelegramNotify `json:"telegram"`
Mail MailNotify `json:"mail"`
Slack SlackNotify `json:"slack"`
}
// Settings struct // Settings struct
type Settings struct { type Settings struct {
Provider string `json:"provider"` Provider string `json:"provider"`
@ -55,16 +30,12 @@ type Settings struct {
LoginToken string `json:"login_token"` LoginToken string `json:"login_token"`
Domains []Domain `json:"domains"` Domains []Domain `json:"domains"`
IPUrl string `json:"ip_url"` IPUrl string `json:"ip_url"`
IPV6Url string `json:"ipv6_url"`
Interval int `json:"interval"`
UserAgent string `json:"user_agent,omitempty"`
LogPath string `json:"log_path"` LogPath string `json:"log_path"`
Socks5Proxy string `json:"socks5_proxy"` Socks5Proxy string `json:"socks5_proxy"`
Notify Notify `json:"notify"` Notify Notify `json:"notify"`
IPInterface string `json:"ip_interface"` IPInterface string `json:"ip_interface"`
IPType string `json:"ip_type"` //the code is not ready to update AAAA record
Resolver string `json:"resolver"` //IPType string `json:"ip_type"`
UseProxy bool `json:"use_proxy"`
} }
// LoadSettings -- Load settings from config file // LoadSettings -- Load settings from config file
@ -82,10 +53,5 @@ func LoadSettings(configPath string, settings *Settings) error {
return err return err
} }
if settings.Interval == 0 {
// set default interval as 5 minutes if interval is 0
settings.Interval = 5 * 60
}
return nil return nil
} }

View File

@ -35,7 +35,7 @@ var mailTemplate = `
<h1 class="size-28" style="Margin-top: 0;Margin-bottom: 0;font-style: normal;font-weight: normal;color: #000;font-size: 24px;line-height: 32px;font-family: avenir,sans-serif;text-align: center;" <h1 class="size-28" style="Margin-top: 0;Margin-bottom: 0;font-style: normal;font-weight: normal;color: #000;font-size: 24px;line-height: 32px;font-family: avenir,sans-serif;text-align: center;"
lang="x-size-28"> lang="x-size-28">
<span class="font-avenir"> <span class="font-avenir">
<span style="color:#ffffff">Your IP address has been changed to</span> <span style="color:#ffffff">Your IP address is changed to</span>
</span> </span>
</h1> </h1>
<h1 class="size-48" style="Margin-top: 20px;Margin-bottom: 0;font-style: normal;font-weight: normal;color: #000;font-size: 36px;line-height: 43px;font-family: avenir,sans-serif;text-align: center;" <h1 class="size-48" style="Margin-top: 20px;Margin-bottom: 0;font-style: normal;font-weight: normal;color: #000;font-size: 36px;line-height: 43px;font-family: avenir,sans-serif;text-align: center;"

316
utils.go
View File

@ -2,20 +2,14 @@ package godns
import ( import (
"bytes" "bytes"
"encoding/json"
"errors" "errors"
"fmt"
"html/template" "html/template"
"io/ioutil" "io/ioutil"
"log" "log"
"net" "net"
"net/http" "net/http"
"net/url"
"strings" "strings"
dnsResolver "github.com/TimothyYe/godns/resolver"
"github.com/miekg/dns"
"golang.org/x/net/proxy" "golang.org/x/net/proxy"
"gopkg.in/gomail.v2" "gopkg.in/gomail.v2"
) )
@ -40,26 +34,14 @@ https://github.com/TimothyYe/godns
const ( const (
// PanicMax is the max allowed panic times // PanicMax is the max allowed panic times
PanicMax = 5 PanicMax = 5
// INTERVAL is minute
INTERVAL = 5
// DNSPOD for dnspod.cn // DNSPOD for dnspod.cn
DNSPOD = "DNSPod" DNSPOD = "DNSPod"
// HE for he.net // HE for he.net
HE = "HE" HE = "HE"
// CLOUDFLARE for cloudflare.com // CLOUDFLARE for cloudflare.com
CLOUDFLARE = "Cloudflare" CLOUDFLARE = "Cloudflare"
// ALIDNS for AliDNS
ALIDNS = "AliDNS"
// GOOGLE for Google Domains
GOOGLE = "Google"
// DUCK for Duck DNS
DUCK = "DuckDNS"
// DREAMHOST for Dreamhost
DREAMHOST = "Dreamhost"
// NOIP for NoIP
NOIP = "NoIP"
// IPV4 for IPV4 mode
IPV4 = "IPV4"
// IPV6 for IPV6 mode
IPV6 = "IPV6"
) )
//GetIPFromInterface gets IP address from the specific interface //GetIPFromInterface gets IP address from the specific interface
@ -98,19 +80,23 @@ func GetIPFromInterface(configuration *Settings) (string, error) {
continue continue
} }
if isIPv4(ip.String()) { //the code is not ready for updating an AAAA record
if strings.ToUpper(configuration.IPType) != IPV4 { /*
continue if (isIPv4(ip.String())){
if (configuration.IPType=="IPv6"){
continue;
} }
}else{ }else{
if strings.ToUpper(configuration.IPType) != IPV6 { if (configuration.IPType!="IPv6"){
continue;
}
} */
if !isIPv4(ip.String()) {
continue continue
} }
}
if ip.String() != "" {
return ip.String(), nil return ip.String(), nil
}
} }
return "", errors.New("can't get a vaild address from " + configuration.IPInterface) return "", errors.New("can't get a vaild address from " + configuration.IPInterface)
} }
@ -119,31 +105,11 @@ func isIPv4(ip string) bool {
return strings.Count(ip, ":") < 2 return strings.Count(ip, ":") < 2
} }
// GetHttpClient creates the HTTP client and return it
func GetHttpClient(configuration *Settings, useProxy bool) *http.Client {
client := &http.Client{}
if useProxy && configuration.Socks5Proxy != "" {
log.Println("use socks5 proxy:" + configuration.Socks5Proxy)
dialer, err := proxy.SOCKS5("tcp", configuration.Socks5Proxy, nil, proxy.Direct)
if err != nil {
log.Println("can't connect to the proxy:", err)
return nil
}
httpTransport := &http.Transport{}
client.Transport = httpTransport
httpTransport.Dial = dialer.Dial
}
return client
}
//GetCurrentIP gets an IP from either internet or specific interface, depending on configuration //GetCurrentIP gets an IP from either internet or specific interface, depending on configuration
func GetCurrentIP(configuration *Settings) (string, error) { func GetCurrentIP(configuration *Settings) (string, error) {
var err error var err error
if configuration.IPUrl != "" || configuration.IPV6Url != "" { if configuration.IPUrl != "" {
ip, err := GetIPOnline(configuration) ip, err := GetIPOnline(configuration)
if err != nil { if err != nil {
log.Println("get ip online failed. Fallback to get ip from interface if possible.") log.Println("get ip online failed. Fallback to get ip from interface if possible.")
@ -168,15 +134,22 @@ func GetCurrentIP(configuration *Settings) (string, error) {
func GetIPOnline(configuration *Settings) (string, error) { func GetIPOnline(configuration *Settings) (string, error) {
client := &http.Client{} client := &http.Client{}
var response *http.Response if configuration.Socks5Proxy != "" {
var err error
if configuration.IPType == "" || strings.ToUpper(configuration.IPType) == IPV4 { log.Println("use socks5 proxy:" + configuration.Socks5Proxy)
response, err = client.Get(configuration.IPUrl) dialer, err := proxy.SOCKS5("tcp", configuration.Socks5Proxy, nil, proxy.Direct)
} else { if err != nil {
response, err = client.Get(configuration.IPV6Url) log.Println("can't connect to the proxy:", err)
return "", err
} }
httpTransport := &http.Transport{}
client.Transport = httpTransport
httpTransport.Dial = dialer.Dial
}
response, err := client.Get(configuration.IPUrl)
if err != nil { if err != nil {
log.Println("Cannot get IP...") log.Println("Cannot get IP...")
return "", err return "", err
@ -190,228 +163,52 @@ func GetIPOnline(configuration *Settings) (string, error) {
// CheckSettings check the format of settings // CheckSettings check the format of settings
func CheckSettings(config *Settings) error { func CheckSettings(config *Settings) error {
switch config.Provider { if config.Provider == DNSPOD {
case DNSPOD:
if config.Password == "" && config.LoginToken == "" { if config.Password == "" && config.LoginToken == "" {
return errors.New("password or login token cannot be empty") return errors.New("password or login token cannot be empty")
} }
case HE: } else if config.Provider == HE {
if config.Password == "" { if config.Password == "" {
return errors.New("password cannot be empty") return errors.New("password cannot be empty")
} }
case CLOUDFLARE: } else if config.Provider == CLOUDFLARE {
if config.LoginToken == "" {
if config.Email == "" { if config.Email == "" {
return errors.New("email cannot be empty") return errors.New("email cannot be empty")
} }
if config.Password == "" { if config.Password == "" {
return errors.New("password cannot be empty") return errors.New("password cannot be empty")
} }
} } else {
case ALIDNS: return errors.New("please provide supported DNS provider: DNSPod/HE")
if config.Email == "" {
return errors.New("email cannot be empty")
}
if config.Password == "" {
return errors.New("password cannot be empty")
}
case DUCK:
if config.LoginToken == "" {
return errors.New("login token cannot be empty")
}
case GOOGLE:
fallthrough
case NOIP:
if config.Email == "" {
return errors.New("email cannot be empty")
}
if config.Password == "" {
return errors.New("password cannot be empty")
}
case DREAMHOST:
if config.LoginToken == "" {
return errors.New("login token cannot be empty")
}
default:
return errors.New("please provide supported DNS provider: DNSPod/HE/AliDNS/Cloudflare/GoogleDomain/DuckDNS/Dreamhost")
} }
return nil return nil
} }
// SendTelegramNotify sends notify if IP is changed // SendNotify sends mail notify if IP is changed
func SendTelegramNotify(configuration *Settings, domain, currentIP string) error { func SendNotify(configuration *Settings, domain, currentIP string) error {
if !configuration.Notify.Telegram.Enabled {
return nil
}
if configuration.Notify.Telegram.BotApiKey == "" {
return errors.New("bot api key cannot be empty")
}
if configuration.Notify.Telegram.ChatId == "" {
return errors.New("chat id cannot be empty")
}
client := GetHttpClient(configuration, configuration.Notify.Telegram.UseProxy)
tpl := configuration.Notify.Telegram.MsgTemplate
if tpl == "" {
tpl = "_Your IP address is changed to_%0A%0A*{{ .CurrentIP }}*%0A%0ADomain *{{ .Domain }}* is updated"
}
msg := buildTemplate(currentIP, domain, tpl)
reqURL := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s&parse_mode=Markdown&text=%s",
configuration.Notify.Telegram.BotApiKey,
configuration.Notify.Telegram.ChatId,
msg)
var response *http.Response
var err error
response, err = client.Get(reqURL)
if err != nil {
return err
}
defer response.Body.Close()
body, _ := ioutil.ReadAll(response.Body)
type ResponseParameters struct {
MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
RetryAfter int `json:"retry_after"` // optional
}
type APIResponse struct {
Ok bool `json:"ok"`
Result json.RawMessage `json:"result"`
ErrorCode int `json:"error_code"`
Description string `json:"description"`
Parameters *ResponseParameters `json:"parameters"`
}
var resp APIResponse
err = json.Unmarshal(body, &resp)
if err != nil {
fmt.Println("error:", err)
return errors.New("failed to parse response")
}
if !resp.Ok {
return errors.New(resp.Description)
}
return nil
}
// SendMailNotify sends mail notify if IP is changed
func SendMailNotify(configuration *Settings, domain, currentIP string) error {
if !configuration.Notify.Mail.Enabled {
return nil
}
log.Print("Sending notification to:", configuration.Notify.Mail.SendTo)
m := gomail.NewMessage() m := gomail.NewMessage()
m.SetHeader("From", configuration.Notify.Mail.SMTPUsername) m.SetHeader("From", configuration.Notify.SMTPUsername)
m.SetHeader("To", configuration.Notify.Mail.SendTo) m.SetHeader("To", configuration.Notify.SendTo)
m.SetHeader("Subject", "GoDNS Notification") m.SetHeader("Subject", "GoDNS Notification")
log.Println("currentIP:", currentIP) log.Println("currentIP:", currentIP)
log.Println("domain:", domain) log.Println("domain:", domain)
m.SetBody("text/html", buildTemplate(currentIP, domain, mailTemplate)) m.SetBody("text/html", buildTemplate(currentIP, domain))
d := gomail.NewDialer(configuration.Notify.Mail.SMTPServer, configuration.Notify.Mail.SMTPPort, configuration.Notify.Mail.SMTPUsername, configuration.Notify.Mail.SMTPPassword) d := gomail.NewPlainDialer(configuration.Notify.SMTPServer, configuration.Notify.SMTPPort, configuration.Notify.SMTPUsername, configuration.Notify.SMTPPassword)
// Send the email config by sendlist . // Send the email config by sendlist .
if err := d.DialAndSend(m); err != nil { if err := d.DialAndSend(m); err != nil {
return err
}
return nil
}
// SendSlack sends slack if IP is changed
func SendSlackNotify(configuration *Settings, domain, currentIP string) error {
if !configuration.Notify.Slack.Enabled {
return nil
}
if configuration.Notify.Slack.BotApiToken == "" {
return errors.New("bot api token cannot be empty")
}
if configuration.Notify.Slack.Channel == "" {
return errors.New("channel cannot be empty")
}
client := GetHttpClient(configuration, configuration.Notify.Slack.UseProxy)
tpl := configuration.Notify.Slack.MsgTemplate
if tpl == "" {
tpl = "_Your IP address is changed to_\n\n*{{ .CurrentIP }}*\n\nDomain *{{ .Domain }}* is updated"
}
msg := buildTemplate(currentIP, domain, tpl)
var response *http.Response
var err error
formData := url.Values{
"token": {configuration.Notify.Slack.BotApiToken},
"channel": {configuration.Notify.Slack.Channel},
"text": {msg},
}
response, err = client.PostForm("https://slack.com/api/chat.postMessage", formData)
if err != nil {
return err
}
defer response.Body.Close()
body, _ := ioutil.ReadAll(response.Body)
type ResponseParameters struct {
MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
RetryAfter int `json:"retry_after"` // optional
}
type APIResponse struct {
Ok bool `json:"ok"`
Result json.RawMessage `json:"result"`
ErrorCode int `json:"error_code"`
Description string `json:"description"`
Parameters *ResponseParameters `json:"parameters"`
}
var resp APIResponse
err = json.Unmarshal(body, &resp)
if err != nil {
fmt.Println("error:", err)
return errors.New("failed to parse response")
}
if !resp.Ok {
return errors.New(resp.Description)
}
return nil
}
// SendNotify sends notify if IP is changed
func SendNotify(configuration *Settings, domain, currentIP string) error {
err := SendTelegramNotify(configuration, domain, currentIP)
if err != nil {
log.Println("Send telegram notification with error:", err.Error())
}
err = SendMailNotify(configuration, domain, currentIP)
if err != nil {
log.Println("Send email notification with error:", err.Error()) log.Println("Send email notification with error:", err.Error())
} return err
err = SendSlackNotify(configuration, domain, currentIP)
if err != nil {
log.Println("Send slack notification with error:", err.Error())
} }
return nil return nil
} }
func buildTemplate(currentIP, domain string, tplsrc string) string { func buildTemplate(currentIP, domain string) string {
t := template.New("notification template") t := template.New("notification template")
if _, err := t.Parse(tplsrc); err != nil { t.Parse(mailTemplate)
log.Println("Failed to parse template")
return ""
}
data := struct { data := struct {
CurrentIP string CurrentIP string
@ -429,34 +226,3 @@ func buildTemplate(currentIP, domain string, tplsrc string) string {
return tpl.String() return tpl.String()
} }
// ResolveDNS will query DNS for a given hostname.
func ResolveDNS(hostname, resolver, ipType string) (string, error) {
var dnsType uint16
if ipType == "" || strings.ToUpper(ipType) == IPV4 {
dnsType = dns.TypeA
} else {
dnsType = dns.TypeAAAA
}
// If no DNS server is set in config file, falls back to default resolver.
if resolver == "" {
dnsAdress, err := net.LookupHost(hostname)
if err != nil {
return "<nil>", err
}
return dnsAdress[0], nil
}
res := dnsResolver.New([]string{resolver})
// In case of i/o timeout
res.RetryTimes = 5
ip, err := res.LookupHost(hostname, dnsType)
if err != nil {
return "<nil>", err
}
return ip[0].String(), nil
}

View File

@ -5,7 +5,7 @@ import (
) )
func TestGetCurrentIP(t *testing.T) { func TestGetCurrentIP(t *testing.T) {
conf := &Settings{IPUrl: "https://myip.biturl.top"} conf := &Settings{IPUrl: "http://members.3322.org/dyndns/getip"}
ip, _ := GetCurrentIP(conf) ip, _ := GetCurrentIP(conf)
if ip == "" { if ip == "" {
@ -13,6 +13,13 @@ func TestGetCurrentIP(t *testing.T) {
} else { } else {
t.Log("IP is:" + ip) t.Log("IP is:" + ip)
} }
conf = &Settings{Socks5Proxy: "localhost:8899", IPUrl: "http://members.3322.org/dyndns/getip"}
ip, err := GetCurrentIP(conf)
if ip != "" && err == nil {
t.Error("should return error")
}
} }
func TestCheckSettings(t *testing.T) { func TestCheckSettings(t *testing.T) {

10
vendor/github.com/bitly/go-simplejson/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,10 @@
language: go
go:
- 1.0.3
- 1.1.2
- 1.2
- tip
install:
- go get github.com/bmizerany/assert
notifications:
email: false

17
vendor/github.com/bitly/go-simplejson/LICENSE generated vendored Normal file
View File

@ -0,0 +1,17 @@
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

13
vendor/github.com/bitly/go-simplejson/README.md generated vendored Normal file
View File

@ -0,0 +1,13 @@
### go-simplejson
a Go package to interact with arbitrary JSON
[![Build Status](https://secure.travis-ci.org/bitly/go-simplejson.png)](http://travis-ci.org/bitly/go-simplejson)
### Importing
import github.com/bitly/go-simplejson
### Documentation
Visit the docs on [gopkgdoc](http://godoc.org/github.com/bitly/go-simplejson)

446
vendor/github.com/bitly/go-simplejson/simplejson.go generated vendored Normal file
View File

@ -0,0 +1,446 @@
package simplejson
import (
"encoding/json"
"errors"
"log"
)
// returns the current implementation version
func Version() string {
return "0.5.0"
}
type Json struct {
data interface{}
}
// NewJson returns a pointer to a new `Json` object
// after unmarshaling `body` bytes
func NewJson(body []byte) (*Json, error) {
j := new(Json)
err := j.UnmarshalJSON(body)
if err != nil {
return nil, err
}
return j, nil
}
// New returns a pointer to a new, empty `Json` object
func New() *Json {
return &Json{
data: make(map[string]interface{}),
}
}
// Interface returns the underlying data
func (j *Json) Interface() interface{} {
return j.data
}
// Encode returns its marshaled data as `[]byte`
func (j *Json) Encode() ([]byte, error) {
return j.MarshalJSON()
}
// EncodePretty returns its marshaled data as `[]byte` with indentation
func (j *Json) EncodePretty() ([]byte, error) {
return json.MarshalIndent(&j.data, "", " ")
}
// Implements the json.Marshaler interface.
func (j *Json) MarshalJSON() ([]byte, error) {
return json.Marshal(&j.data)
}
// Set modifies `Json` map by `key` and `value`
// Useful for changing single key/value in a `Json` object easily.
func (j *Json) Set(key string, val interface{}) {
m, err := j.Map()
if err != nil {
return
}
m[key] = val
}
// SetPath modifies `Json`, recursively checking/creating map keys for the supplied path,
// and then finally writing in the value
func (j *Json) SetPath(branch []string, val interface{}) {
if len(branch) == 0 {
j.data = val
return
}
// in order to insert our branch, we need map[string]interface{}
if _, ok := (j.data).(map[string]interface{}); !ok {
// have to replace with something suitable
j.data = make(map[string]interface{})
}
curr := j.data.(map[string]interface{})
for i := 0; i < len(branch)-1; i++ {
b := branch[i]
// key exists?
if _, ok := curr[b]; !ok {
n := make(map[string]interface{})
curr[b] = n
curr = n
continue
}
// make sure the value is the right sort of thing
if _, ok := curr[b].(map[string]interface{}); !ok {
// have to replace with something suitable
n := make(map[string]interface{})
curr[b] = n
}
curr = curr[b].(map[string]interface{})
}
// add remaining k/v
curr[branch[len(branch)-1]] = val
}
// Del modifies `Json` map by deleting `key` if it is present.
func (j *Json) Del(key string) {
m, err := j.Map()
if err != nil {
return
}
delete(m, key)
}
// Get returns a pointer to a new `Json` object
// for `key` in its `map` representation
//
// useful for chaining operations (to traverse a nested JSON):
// js.Get("top_level").Get("dict").Get("value").Int()
func (j *Json) Get(key string) *Json {
m, err := j.Map()
if err == nil {
if val, ok := m[key]; ok {
return &Json{val}
}
}
return &Json{nil}
}
// GetPath searches for the item as specified by the branch
// without the need to deep dive using Get()'s.
//
// js.GetPath("top_level", "dict")
func (j *Json) GetPath(branch ...string) *Json {
jin := j
for _, p := range branch {
jin = jin.Get(p)
}
return jin
}
// GetIndex returns a pointer to a new `Json` object
// for `index` in its `array` representation
//
// this is the analog to Get when accessing elements of
// a json array instead of a json object:
// js.Get("top_level").Get("array").GetIndex(1).Get("key").Int()
func (j *Json) GetIndex(index int) *Json {
a, err := j.Array()
if err == nil {
if len(a) > index {
return &Json{a[index]}
}
}
return &Json{nil}
}
// CheckGet returns a pointer to a new `Json` object and
// a `bool` identifying success or failure
//
// useful for chained operations when success is important:
// if data, ok := js.Get("top_level").CheckGet("inner"); ok {
// log.Println(data)
// }
func (j *Json) CheckGet(key string) (*Json, bool) {
m, err := j.Map()
if err == nil {
if val, ok := m[key]; ok {
return &Json{val}, true
}
}
return nil, false
}
// Map type asserts to `map`
func (j *Json) Map() (map[string]interface{}, error) {
if m, ok := (j.data).(map[string]interface{}); ok {
return m, nil
}
return nil, errors.New("type assertion to map[string]interface{} failed")
}
// Array type asserts to an `array`
func (j *Json) Array() ([]interface{}, error) {
if a, ok := (j.data).([]interface{}); ok {
return a, nil
}
return nil, errors.New("type assertion to []interface{} failed")
}
// Bool type asserts to `bool`
func (j *Json) Bool() (bool, error) {
if s, ok := (j.data).(bool); ok {
return s, nil
}
return false, errors.New("type assertion to bool failed")
}
// String type asserts to `string`
func (j *Json) String() (string, error) {
if s, ok := (j.data).(string); ok {
return s, nil
}
return "", errors.New("type assertion to string failed")
}
// Bytes type asserts to `[]byte`
func (j *Json) Bytes() ([]byte, error) {
if s, ok := (j.data).(string); ok {
return []byte(s), nil
}
return nil, errors.New("type assertion to []byte failed")
}
// StringArray type asserts to an `array` of `string`
func (j *Json) StringArray() ([]string, error) {
arr, err := j.Array()
if err != nil {
return nil, err
}
retArr := make([]string, 0, len(arr))
for _, a := range arr {
if a == nil {
retArr = append(retArr, "")
continue
}
s, ok := a.(string)
if !ok {
return nil, err
}
retArr = append(retArr, s)
}
return retArr, nil
}
// MustArray guarantees the return of a `[]interface{}` (with optional default)
//
// useful when you want to interate over array values in a succinct manner:
// for i, v := range js.Get("results").MustArray() {
// fmt.Println(i, v)
// }
func (j *Json) MustArray(args ...[]interface{}) []interface{} {
var def []interface{}
switch len(args) {
case 0:
case 1:
def = args[0]
default:
log.Panicf("MustArray() received too many arguments %d", len(args))
}
a, err := j.Array()
if err == nil {
return a
}
return def
}
// MustMap guarantees the return of a `map[string]interface{}` (with optional default)
//
// useful when you want to interate over map values in a succinct manner:
// for k, v := range js.Get("dictionary").MustMap() {
// fmt.Println(k, v)
// }
func (j *Json) MustMap(args ...map[string]interface{}) map[string]interface{} {
var def map[string]interface{}
switch len(args) {
case 0:
case 1:
def = args[0]
default:
log.Panicf("MustMap() received too many arguments %d", len(args))
}
a, err := j.Map()
if err == nil {
return a
}
return def
}
// MustString guarantees the return of a `string` (with optional default)
//
// useful when you explicitly want a `string` in a single value return context:
// myFunc(js.Get("param1").MustString(), js.Get("optional_param").MustString("my_default"))
func (j *Json) MustString(args ...string) string {
var def string
switch len(args) {
case 0:
case 1:
def = args[0]
default:
log.Panicf("MustString() received too many arguments %d", len(args))
}
s, err := j.String()
if err == nil {
return s
}
return def
}
// MustStringArray guarantees the return of a `[]string` (with optional default)
//
// useful when you want to interate over array values in a succinct manner:
// for i, s := range js.Get("results").MustStringArray() {
// fmt.Println(i, s)
// }
func (j *Json) MustStringArray(args ...[]string) []string {
var def []string
switch len(args) {
case 0:
case 1:
def = args[0]
default:
log.Panicf("MustStringArray() received too many arguments %d", len(args))
}
a, err := j.StringArray()
if err == nil {
return a
}
return def
}
// MustInt guarantees the return of an `int` (with optional default)
//
// useful when you explicitly want an `int` in a single value return context:
// myFunc(js.Get("param1").MustInt(), js.Get("optional_param").MustInt(5150))
func (j *Json) MustInt(args ...int) int {
var def int
switch len(args) {
case 0:
case 1:
def = args[0]
default:
log.Panicf("MustInt() received too many arguments %d", len(args))
}
i, err := j.Int()
if err == nil {
return i
}
return def
}
// MustFloat64 guarantees the return of a `float64` (with optional default)
//
// useful when you explicitly want a `float64` in a single value return context:
// myFunc(js.Get("param1").MustFloat64(), js.Get("optional_param").MustFloat64(5.150))
func (j *Json) MustFloat64(args ...float64) float64 {
var def float64
switch len(args) {
case 0:
case 1:
def = args[0]
default:
log.Panicf("MustFloat64() received too many arguments %d", len(args))
}
f, err := j.Float64()
if err == nil {
return f
}
return def
}
// MustBool guarantees the return of a `bool` (with optional default)
//
// useful when you explicitly want a `bool` in a single value return context:
// myFunc(js.Get("param1").MustBool(), js.Get("optional_param").MustBool(true))
func (j *Json) MustBool(args ...bool) bool {
var def bool
switch len(args) {
case 0:
case 1:
def = args[0]
default:
log.Panicf("MustBool() received too many arguments %d", len(args))
}
b, err := j.Bool()
if err == nil {
return b
}
return def
}
// MustInt64 guarantees the return of an `int64` (with optional default)
//
// useful when you explicitly want an `int64` in a single value return context:
// myFunc(js.Get("param1").MustInt64(), js.Get("optional_param").MustInt64(5150))
func (j *Json) MustInt64(args ...int64) int64 {
var def int64
switch len(args) {
case 0:
case 1:
def = args[0]
default:
log.Panicf("MustInt64() received too many arguments %d", len(args))
}
i, err := j.Int64()
if err == nil {
return i
}
return def
}
// MustUInt64 guarantees the return of an `uint64` (with optional default)
//
// useful when you explicitly want an `uint64` in a single value return context:
// myFunc(js.Get("param1").MustUint64(), js.Get("optional_param").MustUint64(5150))
func (j *Json) MustUint64(args ...uint64) uint64 {
var def uint64
switch len(args) {
case 0:
case 1:
def = args[0]
default:
log.Panicf("MustUint64() received too many arguments %d", len(args))
}
i, err := j.Uint64()
if err == nil {
return i
}
return def
}

View File

@ -0,0 +1,75 @@
// +build !go1.1
package simplejson
import (
"encoding/json"
"errors"
"io"
"reflect"
)
// NewFromReader returns a *Json by decoding from an io.Reader
func NewFromReader(r io.Reader) (*Json, error) {
j := new(Json)
dec := json.NewDecoder(r)
err := dec.Decode(&j.data)
return j, err
}
// Implements the json.Unmarshaler interface.
func (j *Json) UnmarshalJSON(p []byte) error {
return json.Unmarshal(p, &j.data)
}
// Float64 coerces into a float64
func (j *Json) Float64() (float64, error) {
switch j.data.(type) {
case float32, float64:
return reflect.ValueOf(j.data).Float(), nil
case int, int8, int16, int32, int64:
return float64(reflect.ValueOf(j.data).Int()), nil
case uint, uint8, uint16, uint32, uint64:
return float64(reflect.ValueOf(j.data).Uint()), nil
}
return 0, errors.New("invalid value type")
}
// Int coerces into an int
func (j *Json) Int() (int, error) {
switch j.data.(type) {
case float32, float64:
return int(reflect.ValueOf(j.data).Float()), nil
case int, int8, int16, int32, int64:
return int(reflect.ValueOf(j.data).Int()), nil
case uint, uint8, uint16, uint32, uint64:
return int(reflect.ValueOf(j.data).Uint()), nil
}
return 0, errors.New("invalid value type")
}
// Int64 coerces into an int64
func (j *Json) Int64() (int64, error) {
switch j.data.(type) {
case float32, float64:
return int64(reflect.ValueOf(j.data).Float()), nil
case int, int8, int16, int32, int64:
return reflect.ValueOf(j.data).Int(), nil
case uint, uint8, uint16, uint32, uint64:
return int64(reflect.ValueOf(j.data).Uint()), nil
}
return 0, errors.New("invalid value type")
}
// Uint64 coerces into an uint64
func (j *Json) Uint64() (uint64, error) {
switch j.data.(type) {
case float32, float64:
return uint64(reflect.ValueOf(j.data).Float()), nil
case int, int8, int16, int32, int64:
return uint64(reflect.ValueOf(j.data).Int()), nil
case uint, uint8, uint16, uint32, uint64:
return reflect.ValueOf(j.data).Uint(), nil
}
return 0, errors.New("invalid value type")
}

View File

@ -0,0 +1,89 @@
// +build go1.1
package simplejson
import (
"bytes"
"encoding/json"
"errors"
"io"
"reflect"
"strconv"
)
// Implements the json.Unmarshaler interface.
func (j *Json) UnmarshalJSON(p []byte) error {
dec := json.NewDecoder(bytes.NewBuffer(p))
dec.UseNumber()
return dec.Decode(&j.data)
}
// NewFromReader returns a *Json by decoding from an io.Reader
func NewFromReader(r io.Reader) (*Json, error) {
j := new(Json)
dec := json.NewDecoder(r)
dec.UseNumber()
err := dec.Decode(&j.data)
return j, err
}
// Float64 coerces into a float64
func (j *Json) Float64() (float64, error) {
switch j.data.(type) {
case json.Number:
return j.data.(json.Number).Float64()
case float32, float64:
return reflect.ValueOf(j.data).Float(), nil
case int, int8, int16, int32, int64:
return float64(reflect.ValueOf(j.data).Int()), nil
case uint, uint8, uint16, uint32, uint64:
return float64(reflect.ValueOf(j.data).Uint()), nil
}
return 0, errors.New("invalid value type")
}
// Int coerces into an int
func (j *Json) Int() (int, error) {
switch j.data.(type) {
case json.Number:
i, err := j.data.(json.Number).Int64()
return int(i), err
case float32, float64:
return int(reflect.ValueOf(j.data).Float()), nil
case int, int8, int16, int32, int64:
return int(reflect.ValueOf(j.data).Int()), nil
case uint, uint8, uint16, uint32, uint64:
return int(reflect.ValueOf(j.data).Uint()), nil
}
return 0, errors.New("invalid value type")
}
// Int64 coerces into an int64
func (j *Json) Int64() (int64, error) {
switch j.data.(type) {
case json.Number:
return j.data.(json.Number).Int64()
case float32, float64:
return int64(reflect.ValueOf(j.data).Float()), nil
case int, int8, int16, int32, int64:
return reflect.ValueOf(j.data).Int(), nil
case uint, uint8, uint16, uint32, uint64:
return int64(reflect.ValueOf(j.data).Uint()), nil
}
return 0, errors.New("invalid value type")
}
// Uint64 coerces into an uint64
func (j *Json) Uint64() (uint64, error) {
switch j.data.(type) {
case json.Number:
return strconv.ParseUint(j.data.(json.Number).String(), 10, 64)
case float32, float64:
return uint64(reflect.ValueOf(j.data).Float()), nil
case int, int8, int16, int32, int64:
return uint64(reflect.ValueOf(j.data).Int()), nil
case uint, uint8, uint16, uint32, uint64:
return reflect.ValueOf(j.data).Uint(), nil
}
return 0, errors.New("invalid value type")
}

5
vendor/github.com/fatih/color/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,5 @@
language: go
go:
- 1.8.x
- tip

27
vendor/github.com/fatih/color/Gopkg.lock generated vendored Normal file
View File

@ -0,0 +1,27 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/mattn/go-colorable"
packages = ["."]
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
version = "v0.0.9"
[[projects]]
name = "github.com/mattn/go-isatty"
packages = ["."]
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "e8a50671c3cb93ea935bf210b1cd20702876b9d9226129be581ef646d1565cdc"
solver-name = "gps-cdcl"
solver-version = 1

30
vendor/github.com/fatih/color/Gopkg.toml generated vendored Normal file
View File

@ -0,0 +1,30 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
name = "github.com/mattn/go-colorable"
version = "0.0.9"
[[constraint]]
name = "github.com/mattn/go-isatty"
version = "0.0.3"

20
vendor/github.com/fatih/color/LICENSE.md generated vendored Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 Fatih Arslan
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

179
vendor/github.com/fatih/color/README.md generated vendored Normal file
View File

@ -0,0 +1,179 @@
# Color [![GoDoc](https://godoc.org/github.com/fatih/color?status.svg)](https://godoc.org/github.com/fatih/color) [![Build Status](https://img.shields.io/travis/fatih/color.svg?style=flat-square)](https://travis-ci.org/fatih/color)
Color lets you use colorized outputs in terms of [ANSI Escape
Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It
has support for Windows too! The API can be used in several ways, pick one that
suits you.
![Color](https://i.imgur.com/c1JI0lA.png)
## Install
```bash
go get github.com/fatih/color
```
Note that the `vendor` folder is here for stability. Remove the folder if you
already have the dependencies in your GOPATH.
## Examples
### Standard colors
```go
// Print with default helper functions
color.Cyan("Prints text in cyan.")
// A newline will be appended automatically
color.Blue("Prints %s in blue.", "text")
// These are using the default foreground colors
color.Red("We have red")
color.Magenta("And many others ..")
```
### Mix and reuse colors
```go
// Create a new color object
c := color.New(color.FgCyan).Add(color.Underline)
c.Println("Prints cyan text with an underline.")
// Or just add them to New()
d := color.New(color.FgCyan, color.Bold)
d.Printf("This prints bold cyan %s\n", "too!.")
// Mix up foreground and background colors, create new mixes!
red := color.New(color.FgRed)
boldRed := red.Add(color.Bold)
boldRed.Println("This will print text in bold red.")
whiteBackground := red.Add(color.BgWhite)
whiteBackground.Println("Red text with white background.")
```
### Use your own output (io.Writer)
```go
// Use your own io.Writer output
color.New(color.FgBlue).Fprintln(myWriter, "blue color!")
blue := color.New(color.FgBlue)
blue.Fprint(writer, "This will print text in blue.")
```
### Custom print functions (PrintFunc)
```go
// Create a custom print function for convenience
red := color.New(color.FgRed).PrintfFunc()
red("Warning")
red("Error: %s", err)
// Mix up multiple attributes
notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
notice("Don't forget this...")
```
### Custom fprint functions (FprintFunc)
```go
blue := color.New(FgBlue).FprintfFunc()
blue(myWriter, "important notice: %s", stars)
// Mix up with multiple attributes
success := color.New(color.Bold, color.FgGreen).FprintlnFunc()
success(myWriter, "Don't forget this...")
```
### Insert into noncolor strings (SprintFunc)
```go
// Create SprintXxx functions to mix strings with other non-colorized strings:
yellow := color.New(color.FgYellow).SprintFunc()
red := color.New(color.FgRed).SprintFunc()
fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error"))
info := color.New(color.FgWhite, color.BgGreen).SprintFunc()
fmt.Printf("This %s rocks!\n", info("package"))
// Use helper functions
fmt.Println("This", color.RedString("warning"), "should be not neglected.")
fmt.Printf("%v %v\n", color.GreenString("Info:"), "an important message.")
// Windows supported too! Just don't forget to change the output to color.Output
fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
```
### Plug into existing code
```go
// Use handy standard colors
color.Set(color.FgYellow)
fmt.Println("Existing text will now be in yellow")
fmt.Printf("This one %s\n", "too")
color.Unset() // Don't forget to unset
// You can mix up parameters
color.Set(color.FgMagenta, color.Bold)
defer color.Unset() // Use it in your function
fmt.Println("All text will now be bold magenta.")
```
### Disable/Enable color
There might be a case where you want to explicitly disable/enable color output. the
`go-isatty` package will automatically disable color output for non-tty output streams
(for example if the output were piped directly to `less`)
`Color` has support to disable/enable colors both globally and for single color
definitions. For example suppose you have a CLI app and a `--no-color` bool flag. You
can easily disable the color output with:
```go
var flagNoColor = flag.Bool("no-color", false, "Disable color output")
if *flagNoColor {
color.NoColor = true // disables colorized output
}
```
It also has support for single color definitions (local). You can
disable/enable color output on the fly:
```go
c := color.New(color.FgCyan)
c.Println("Prints cyan text")
c.DisableColor()
c.Println("This is printed without any color")
c.EnableColor()
c.Println("This prints again cyan...")
```
## Todo
* Save/Return previous values
* Evaluate fmt.Formatter interface
## Credits
* [Fatih Arslan](https://github.com/fatih)
* Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable)
## License
The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details

603
vendor/github.com/fatih/color/color.go generated vendored Normal file
View File

@ -0,0 +1,603 @@
package color
import (
"fmt"
"io"
"os"
"strconv"
"strings"
"sync"
"github.com/mattn/go-colorable"
"github.com/mattn/go-isatty"
)
var (
// NoColor defines if the output is colorized or not. It's dynamically set to
// false or true based on the stdout's file descriptor referring to a terminal
// or not. This is a global option and affects all colors. For more control
// over each color block use the methods DisableColor() individually.
NoColor = os.Getenv("TERM") == "dumb" ||
(!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd()))
// Output defines the standard output of the print functions. By default
// os.Stdout is used.
Output = colorable.NewColorableStdout()
// Error defines a color supporting writer for os.Stderr.
Error = colorable.NewColorableStderr()
// colorsCache is used to reduce the count of created Color objects and
// allows to reuse already created objects with required Attribute.
colorsCache = make(map[Attribute]*Color)
colorsCacheMu sync.Mutex // protects colorsCache
)
// Color defines a custom color object which is defined by SGR parameters.
type Color struct {
params []Attribute
noColor *bool
}
// Attribute defines a single SGR Code
type Attribute int
const escape = "\x1b"
// Base attributes
const (
Reset Attribute = iota
Bold
Faint
Italic
Underline
BlinkSlow
BlinkRapid
ReverseVideo
Concealed
CrossedOut
)
// Foreground text colors
const (
FgBlack Attribute = iota + 30
FgRed
FgGreen
FgYellow
FgBlue
FgMagenta
FgCyan
FgWhite
)
// Foreground Hi-Intensity text colors
const (
FgHiBlack Attribute = iota + 90
FgHiRed
FgHiGreen
FgHiYellow
FgHiBlue
FgHiMagenta
FgHiCyan
FgHiWhite
)
// Background text colors
const (
BgBlack Attribute = iota + 40
BgRed
BgGreen
BgYellow
BgBlue
BgMagenta
BgCyan
BgWhite
)
// Background Hi-Intensity text colors
const (
BgHiBlack Attribute = iota + 100
BgHiRed
BgHiGreen
BgHiYellow
BgHiBlue
BgHiMagenta
BgHiCyan
BgHiWhite
)
// New returns a newly created color object.
func New(value ...Attribute) *Color {
c := &Color{params: make([]Attribute, 0)}
c.Add(value...)
return c
}
// Set sets the given parameters immediately. It will change the color of
// output with the given SGR parameters until color.Unset() is called.
func Set(p ...Attribute) *Color {
c := New(p...)
c.Set()
return c
}
// Unset resets all escape attributes and clears the output. Usually should
// be called after Set().
func Unset() {
if NoColor {
return
}
fmt.Fprintf(Output, "%s[%dm", escape, Reset)
}
// Set sets the SGR sequence.
func (c *Color) Set() *Color {
if c.isNoColorSet() {
return c
}
fmt.Fprintf(Output, c.format())
return c
}
func (c *Color) unset() {
if c.isNoColorSet() {
return
}
Unset()
}
func (c *Color) setWriter(w io.Writer) *Color {
if c.isNoColorSet() {
return c
}
fmt.Fprintf(w, c.format())
return c
}
func (c *Color) unsetWriter(w io.Writer) {
if c.isNoColorSet() {
return
}
if NoColor {
return
}
fmt.Fprintf(w, "%s[%dm", escape, Reset)
}
// Add is used to chain SGR parameters. Use as many as parameters to combine
// and create custom color objects. Example: Add(color.FgRed, color.Underline).
func (c *Color) Add(value ...Attribute) *Color {
c.params = append(c.params, value...)
return c
}
func (c *Color) prepend(value Attribute) {
c.params = append(c.params, 0)
copy(c.params[1:], c.params[0:])
c.params[0] = value
}
// Fprint formats using the default formats for its operands and writes to w.
// Spaces are added between operands when neither is a string.
// It returns the number of bytes written and any write error encountered.
// On Windows, users should wrap w with colorable.NewColorable() if w is of
// type *os.File.
func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
c.setWriter(w)
defer c.unsetWriter(w)
return fmt.Fprint(w, a...)
}
// Print formats using the default formats for its operands and writes to
// standard output. Spaces are added between operands when neither is a
// string. It returns the number of bytes written and any write error
// encountered. This is the standard fmt.Print() method wrapped with the given
// color.
func (c *Color) Print(a ...interface{}) (n int, err error) {
c.Set()
defer c.unset()
return fmt.Fprint(Output, a...)
}
// Fprintf formats according to a format specifier and writes to w.
// It returns the number of bytes written and any write error encountered.
// On Windows, users should wrap w with colorable.NewColorable() if w is of
// type *os.File.
func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
c.setWriter(w)
defer c.unsetWriter(w)
return fmt.Fprintf(w, format, a...)
}
// Printf formats according to a format specifier and writes to standard output.
// It returns the number of bytes written and any write error encountered.
// This is the standard fmt.Printf() method wrapped with the given color.
func (c *Color) Printf(format string, a ...interface{}) (n int, err error) {
c.Set()
defer c.unset()
return fmt.Fprintf(Output, format, a...)
}
// Fprintln formats using the default formats for its operands and writes to w.
// Spaces are always added between operands and a newline is appended.
// On Windows, users should wrap w with colorable.NewColorable() if w is of
// type *os.File.
func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
c.setWriter(w)
defer c.unsetWriter(w)
return fmt.Fprintln(w, a...)
}
// Println formats using the default formats for its operands and writes to
// standard output. Spaces are always added between operands and a newline is
// appended. It returns the number of bytes written and any write error
// encountered. This is the standard fmt.Print() method wrapped with the given
// color.
func (c *Color) Println(a ...interface{}) (n int, err error) {
c.Set()
defer c.unset()
return fmt.Fprintln(Output, a...)
}
// Sprint is just like Print, but returns a string instead of printing it.
func (c *Color) Sprint(a ...interface{}) string {
return c.wrap(fmt.Sprint(a...))
}
// Sprintln is just like Println, but returns a string instead of printing it.
func (c *Color) Sprintln(a ...interface{}) string {
return c.wrap(fmt.Sprintln(a...))
}
// Sprintf is just like Printf, but returns a string instead of printing it.
func (c *Color) Sprintf(format string, a ...interface{}) string {
return c.wrap(fmt.Sprintf(format, a...))
}
// FprintFunc returns a new function that prints the passed arguments as
// colorized with color.Fprint().
func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) {
return func(w io.Writer, a ...interface{}) {
c.Fprint(w, a...)
}
}
// PrintFunc returns a new function that prints the passed arguments as
// colorized with color.Print().
func (c *Color) PrintFunc() func(a ...interface{}) {
return func(a ...interface{}) {
c.Print(a...)
}
}
// FprintfFunc returns a new function that prints the passed arguments as
// colorized with color.Fprintf().
func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) {
return func(w io.Writer, format string, a ...interface{}) {
c.Fprintf(w, format, a...)
}
}
// PrintfFunc returns a new function that prints the passed arguments as
// colorized with color.Printf().
func (c *Color) PrintfFunc() func(format string, a ...interface{}) {
return func(format string, a ...interface{}) {
c.Printf(format, a...)
}
}
// FprintlnFunc returns a new function that prints the passed arguments as
// colorized with color.Fprintln().
func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) {
return func(w io.Writer, a ...interface{}) {
c.Fprintln(w, a...)
}
}
// PrintlnFunc returns a new function that prints the passed arguments as
// colorized with color.Println().
func (c *Color) PrintlnFunc() func(a ...interface{}) {
return func(a ...interface{}) {
c.Println(a...)
}
}
// SprintFunc returns a new function that returns colorized strings for the
// given arguments with fmt.Sprint(). Useful to put into or mix into other
// string. Windows users should use this in conjunction with color.Output, example:
//
// put := New(FgYellow).SprintFunc()
// fmt.Fprintf(color.Output, "This is a %s", put("warning"))
func (c *Color) SprintFunc() func(a ...interface{}) string {
return func(a ...interface{}) string {
return c.wrap(fmt.Sprint(a...))
}
}
// SprintfFunc returns a new function that returns colorized strings for the
// given arguments with fmt.Sprintf(). Useful to put into or mix into other
// string. Windows users should use this in conjunction with color.Output.
func (c *Color) SprintfFunc() func(format string, a ...interface{}) string {
return func(format string, a ...interface{}) string {
return c.wrap(fmt.Sprintf(format, a...))
}
}
// SprintlnFunc returns a new function that returns colorized strings for the
// given arguments with fmt.Sprintln(). Useful to put into or mix into other
// string. Windows users should use this in conjunction with color.Output.
func (c *Color) SprintlnFunc() func(a ...interface{}) string {
return func(a ...interface{}) string {
return c.wrap(fmt.Sprintln(a...))
}
}
// sequence returns a formatted SGR sequence to be plugged into a "\x1b[...m"
// an example output might be: "1;36" -> bold cyan
func (c *Color) sequence() string {
format := make([]string, len(c.params))
for i, v := range c.params {
format[i] = strconv.Itoa(int(v))
}
return strings.Join(format, ";")
}
// wrap wraps the s string with the colors attributes. The string is ready to
// be printed.
func (c *Color) wrap(s string) string {
if c.isNoColorSet() {
return s
}
return c.format() + s + c.unformat()
}
func (c *Color) format() string {
return fmt.Sprintf("%s[%sm", escape, c.sequence())
}
func (c *Color) unformat() string {
return fmt.Sprintf("%s[%dm", escape, Reset)
}
// DisableColor disables the color output. Useful to not change any existing
// code and still being able to output. Can be used for flags like
// "--no-color". To enable back use EnableColor() method.
func (c *Color) DisableColor() {
c.noColor = boolPtr(true)
}
// EnableColor enables the color output. Use it in conjunction with
// DisableColor(). Otherwise this method has no side effects.
func (c *Color) EnableColor() {
c.noColor = boolPtr(false)
}
func (c *Color) isNoColorSet() bool {
// check first if we have user setted action
if c.noColor != nil {
return *c.noColor
}
// if not return the global option, which is disabled by default
return NoColor
}
// Equals returns a boolean value indicating whether two colors are equal.
func (c *Color) Equals(c2 *Color) bool {
if len(c.params) != len(c2.params) {
return false
}
for _, attr := range c.params {
if !c2.attrExists(attr) {
return false
}
}
return true
}
func (c *Color) attrExists(a Attribute) bool {
for _, attr := range c.params {
if attr == a {
return true
}
}
return false
}
func boolPtr(v bool) *bool {
return &v
}
func getCachedColor(p Attribute) *Color {
colorsCacheMu.Lock()
defer colorsCacheMu.Unlock()
c, ok := colorsCache[p]
if !ok {
c = New(p)
colorsCache[p] = c
}
return c
}
func colorPrint(format string, p Attribute, a ...interface{}) {
c := getCachedColor(p)
if !strings.HasSuffix(format, "\n") {
format += "\n"
}
if len(a) == 0 {
c.Print(format)
} else {
c.Printf(format, a...)
}
}
func colorString(format string, p Attribute, a ...interface{}) string {
c := getCachedColor(p)
if len(a) == 0 {
return c.SprintFunc()(format)
}
return c.SprintfFunc()(format, a...)
}
// Black is a convenient helper function to print with black foreground. A
// newline is appended to format by default.
func Black(format string, a ...interface{}) { colorPrint(format, FgBlack, a...) }
// Red is a convenient helper function to print with red foreground. A
// newline is appended to format by default.
func Red(format string, a ...interface{}) { colorPrint(format, FgRed, a...) }
// Green is a convenient helper function to print with green foreground. A
// newline is appended to format by default.
func Green(format string, a ...interface{}) { colorPrint(format, FgGreen, a...) }
// Yellow is a convenient helper function to print with yellow foreground.
// A newline is appended to format by default.
func Yellow(format string, a ...interface{}) { colorPrint(format, FgYellow, a...) }
// Blue is a convenient helper function to print with blue foreground. A
// newline is appended to format by default.
func Blue(format string, a ...interface{}) { colorPrint(format, FgBlue, a...) }
// Magenta is a convenient helper function to print with magenta foreground.
// A newline is appended to format by default.
func Magenta(format string, a ...interface{}) { colorPrint(format, FgMagenta, a...) }
// Cyan is a convenient helper function to print with cyan foreground. A
// newline is appended to format by default.
func Cyan(format string, a ...interface{}) { colorPrint(format, FgCyan, a...) }
// White is a convenient helper function to print with white foreground. A
// newline is appended to format by default.
func White(format string, a ...interface{}) { colorPrint(format, FgWhite, a...) }
// BlackString is a convenient helper function to return a string with black
// foreground.
func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) }
// RedString is a convenient helper function to return a string with red
// foreground.
func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) }
// GreenString is a convenient helper function to return a string with green
// foreground.
func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) }
// YellowString is a convenient helper function to return a string with yellow
// foreground.
func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) }
// BlueString is a convenient helper function to return a string with blue
// foreground.
func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) }
// MagentaString is a convenient helper function to return a string with magenta
// foreground.
func MagentaString(format string, a ...interface{}) string {
return colorString(format, FgMagenta, a...)
}
// CyanString is a convenient helper function to return a string with cyan
// foreground.
func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) }
// WhiteString is a convenient helper function to return a string with white
// foreground.
func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) }
// HiBlack is a convenient helper function to print with hi-intensity black foreground. A
// newline is appended to format by default.
func HiBlack(format string, a ...interface{}) { colorPrint(format, FgHiBlack, a...) }
// HiRed is a convenient helper function to print with hi-intensity red foreground. A
// newline is appended to format by default.
func HiRed(format string, a ...interface{}) { colorPrint(format, FgHiRed, a...) }
// HiGreen is a convenient helper function to print with hi-intensity green foreground. A
// newline is appended to format by default.
func HiGreen(format string, a ...interface{}) { colorPrint(format, FgHiGreen, a...) }
// HiYellow is a convenient helper function to print with hi-intensity yellow foreground.
// A newline is appended to format by default.
func HiYellow(format string, a ...interface{}) { colorPrint(format, FgHiYellow, a...) }
// HiBlue is a convenient helper function to print with hi-intensity blue foreground. A
// newline is appended to format by default.
func HiBlue(format string, a ...interface{}) { colorPrint(format, FgHiBlue, a...) }
// HiMagenta is a convenient helper function to print with hi-intensity magenta foreground.
// A newline is appended to format by default.
func HiMagenta(format string, a ...interface{}) { colorPrint(format, FgHiMagenta, a...) }
// HiCyan is a convenient helper function to print with hi-intensity cyan foreground. A
// newline is appended to format by default.
func HiCyan(format string, a ...interface{}) { colorPrint(format, FgHiCyan, a...) }
// HiWhite is a convenient helper function to print with hi-intensity white foreground. A
// newline is appended to format by default.
func HiWhite(format string, a ...interface{}) { colorPrint(format, FgHiWhite, a...) }
// HiBlackString is a convenient helper function to return a string with hi-intensity black
// foreground.
func HiBlackString(format string, a ...interface{}) string {
return colorString(format, FgHiBlack, a...)
}
// HiRedString is a convenient helper function to return a string with hi-intensity red
// foreground.
func HiRedString(format string, a ...interface{}) string { return colorString(format, FgHiRed, a...) }
// HiGreenString is a convenient helper function to return a string with hi-intensity green
// foreground.
func HiGreenString(format string, a ...interface{}) string {
return colorString(format, FgHiGreen, a...)
}
// HiYellowString is a convenient helper function to return a string with hi-intensity yellow
// foreground.
func HiYellowString(format string, a ...interface{}) string {
return colorString(format, FgHiYellow, a...)
}
// HiBlueString is a convenient helper function to return a string with hi-intensity blue
// foreground.
func HiBlueString(format string, a ...interface{}) string { return colorString(format, FgHiBlue, a...) }
// HiMagentaString is a convenient helper function to return a string with hi-intensity magenta
// foreground.
func HiMagentaString(format string, a ...interface{}) string {
return colorString(format, FgHiMagenta, a...)
}
// HiCyanString is a convenient helper function to return a string with hi-intensity cyan
// foreground.
func HiCyanString(format string, a ...interface{}) string { return colorString(format, FgHiCyan, a...) }
// HiWhiteString is a convenient helper function to return a string with hi-intensity white
// foreground.
func HiWhiteString(format string, a ...interface{}) string {
return colorString(format, FgHiWhite, a...)
}

133
vendor/github.com/fatih/color/doc.go generated vendored Normal file
View File

@ -0,0 +1,133 @@
/*
Package color is an ANSI color package to output colorized or SGR defined
output to the standard output. The API can be used in several way, pick one
that suits you.
Use simple and default helper functions with predefined foreground colors:
color.Cyan("Prints text in cyan.")
// a newline will be appended automatically
color.Blue("Prints %s in blue.", "text")
// More default foreground colors..
color.Red("We have red")
color.Yellow("Yellow color too!")
color.Magenta("And many others ..")
// Hi-intensity colors
color.HiGreen("Bright green color.")
color.HiBlack("Bright black means gray..")
color.HiWhite("Shiny white color!")
However there are times where custom color mixes are required. Below are some
examples to create custom color objects and use the print functions of each
separate color object.
// Create a new color object
c := color.New(color.FgCyan).Add(color.Underline)
c.Println("Prints cyan text with an underline.")
// Or just add them to New()
d := color.New(color.FgCyan, color.Bold)
d.Printf("This prints bold cyan %s\n", "too!.")
// Mix up foreground and background colors, create new mixes!
red := color.New(color.FgRed)
boldRed := red.Add(color.Bold)
boldRed.Println("This will print text in bold red.")
whiteBackground := red.Add(color.BgWhite)
whiteBackground.Println("Red text with White background.")
// Use your own io.Writer output
color.New(color.FgBlue).Fprintln(myWriter, "blue color!")
blue := color.New(color.FgBlue)
blue.Fprint(myWriter, "This will print text in blue.")
You can create PrintXxx functions to simplify even more:
// Create a custom print function for convenient
red := color.New(color.FgRed).PrintfFunc()
red("warning")
red("error: %s", err)
// Mix up multiple attributes
notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
notice("don't forget this...")
You can also FprintXxx functions to pass your own io.Writer:
blue := color.New(FgBlue).FprintfFunc()
blue(myWriter, "important notice: %s", stars)
// Mix up with multiple attributes
success := color.New(color.Bold, color.FgGreen).FprintlnFunc()
success(myWriter, don't forget this...")
Or create SprintXxx functions to mix strings with other non-colorized strings:
yellow := New(FgYellow).SprintFunc()
red := New(FgRed).SprintFunc()
fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error"))
info := New(FgWhite, BgGreen).SprintFunc()
fmt.Printf("this %s rocks!\n", info("package"))
Windows support is enabled by default. All Print functions work as intended.
However only for color.SprintXXX functions, user should use fmt.FprintXXX and
set the output to color.Output:
fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
info := New(FgWhite, BgGreen).SprintFunc()
fmt.Fprintf(color.Output, "this %s rocks!\n", info("package"))
Using with existing code is possible. Just use the Set() method to set the
standard output to the given parameters. That way a rewrite of an existing
code is not required.
// Use handy standard colors.
color.Set(color.FgYellow)
fmt.Println("Existing text will be now in Yellow")
fmt.Printf("This one %s\n", "too")
color.Unset() // don't forget to unset
// You can mix up parameters
color.Set(color.FgMagenta, color.Bold)
defer color.Unset() // use it in your function
fmt.Println("All text will be now bold magenta.")
There might be a case where you want to disable color output (for example to
pipe the standard output of your app to somewhere else). `Color` has support to
disable colors both globally and for single color definition. For example
suppose you have a CLI app and a `--no-color` bool flag. You can easily disable
the color output with:
var flagNoColor = flag.Bool("no-color", false, "Disable color output")
if *flagNoColor {
color.NoColor = true // disables colorized output
}
It also has support for single color definitions (local). You can
disable/enable color output on the fly:
c := color.New(color.FgCyan)
c.Println("Prints cyan text")
c.DisableColor()
c.Println("This is printed without any color")
c.EnableColor()
c.Println("This prints again cyan...")
*/
package color

9
vendor/github.com/mattn/go-colorable/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,9 @@
language: go
go:
- tip
before_install:
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
script:
- $HOME/gopath/bin/goveralls -repotoken xnXqRGwgW3SXIguzxf90ZSK1GPYZPaGrw

21
vendor/github.com/mattn/go-colorable/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Yasuhiro Matsumoto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

48
vendor/github.com/mattn/go-colorable/README.md generated vendored Normal file
View File

@ -0,0 +1,48 @@
# go-colorable
[![Godoc Reference](https://godoc.org/github.com/mattn/go-colorable?status.svg)](http://godoc.org/github.com/mattn/go-colorable)
[![Build Status](https://travis-ci.org/mattn/go-colorable.svg?branch=master)](https://travis-ci.org/mattn/go-colorable)
[![Coverage Status](https://coveralls.io/repos/github/mattn/go-colorable/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-colorable?branch=master)
[![Go Report Card](https://goreportcard.com/badge/mattn/go-colorable)](https://goreportcard.com/report/mattn/go-colorable)
Colorable writer for windows.
For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.)
This package is possible to handle escape sequence for ansi color on windows.
## Too Bad!
![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png)
## So Good!
![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png)
## Usage
```go
logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
logrus.SetOutput(colorable.NewColorableStdout())
logrus.Info("succeeded")
logrus.Warn("not correct")
logrus.Error("something error")
logrus.Fatal("panic")
```
You can compile above code on non-windows OSs.
## Installation
```
$ go get github.com/mattn/go-colorable
```
# License
MIT
# Author
Yasuhiro Matsumoto (a.k.a mattn)

View File

@ -0,0 +1,29 @@
// +build appengine
package colorable
import (
"io"
"os"
_ "github.com/mattn/go-isatty"
)
// NewColorable return new instance of Writer which handle escape sequence.
func NewColorable(file *os.File) io.Writer {
if file == nil {
panic("nil passed instead of *os.File to NewColorable()")
}
return file
}
// NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
func NewColorableStdout() io.Writer {
return os.Stdout
}
// NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
func NewColorableStderr() io.Writer {
return os.Stderr
}

View File

@ -0,0 +1,30 @@
// +build !windows
// +build !appengine
package colorable
import (
"io"
"os"
_ "github.com/mattn/go-isatty"
)
// NewColorable return new instance of Writer which handle escape sequence.
func NewColorable(file *os.File) io.Writer {
if file == nil {
panic("nil passed instead of *os.File to NewColorable()")
}
return file
}
// NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
func NewColorableStdout() io.Writer {
return os.Stdout
}
// NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
func NewColorableStderr() io.Writer {
return os.Stderr
}

View File

@ -0,0 +1,884 @@
// +build windows
// +build !appengine
package colorable
import (
"bytes"
"io"
"math"
"os"
"strconv"
"strings"
"syscall"
"unsafe"
"github.com/mattn/go-isatty"
)
const (
foregroundBlue = 0x1
foregroundGreen = 0x2
foregroundRed = 0x4
foregroundIntensity = 0x8
foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
backgroundBlue = 0x10
backgroundGreen = 0x20
backgroundRed = 0x40
backgroundIntensity = 0x80
backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
)
type wchar uint16
type short int16
type dword uint32
type word uint16
type coord struct {
x short
y short
}
type smallRect struct {
left short
top short
right short
bottom short
}
type consoleScreenBufferInfo struct {
size coord
cursorPosition coord
attributes word
window smallRect
maximumWindowSize coord
}
type consoleCursorInfo struct {
size dword
visible int32
}
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW")
)
// Writer provide colorable Writer to the console
type Writer struct {
out io.Writer
handle syscall.Handle
oldattr word
oldpos coord
}
// NewColorable return new instance of Writer which handle escape sequence from File.
func NewColorable(file *os.File) io.Writer {
if file == nil {
panic("nil passed instead of *os.File to NewColorable()")
}
if isatty.IsTerminal(file.Fd()) {
var csbi consoleScreenBufferInfo
handle := syscall.Handle(file.Fd())
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
return &Writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}}
}
return file
}
// NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
func NewColorableStdout() io.Writer {
return NewColorable(os.Stdout)
}
// NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
func NewColorableStderr() io.Writer {
return NewColorable(os.Stderr)
}
var color256 = map[int]int{
0: 0x000000,
1: 0x800000,
2: 0x008000,
3: 0x808000,
4: 0x000080,
5: 0x800080,
6: 0x008080,
7: 0xc0c0c0,
8: 0x808080,
9: 0xff0000,
10: 0x00ff00,
11: 0xffff00,
12: 0x0000ff,
13: 0xff00ff,
14: 0x00ffff,
15: 0xffffff,
16: 0x000000,
17: 0x00005f,
18: 0x000087,
19: 0x0000af,
20: 0x0000d7,
21: 0x0000ff,
22: 0x005f00,
23: 0x005f5f,
24: 0x005f87,
25: 0x005faf,
26: 0x005fd7,
27: 0x005fff,
28: 0x008700,
29: 0x00875f,
30: 0x008787,
31: 0x0087af,
32: 0x0087d7,
33: 0x0087ff,
34: 0x00af00,
35: 0x00af5f,
36: 0x00af87,
37: 0x00afaf,
38: 0x00afd7,
39: 0x00afff,
40: 0x00d700,
41: 0x00d75f,
42: 0x00d787,
43: 0x00d7af,
44: 0x00d7d7,
45: 0x00d7ff,
46: 0x00ff00,
47: 0x00ff5f,
48: 0x00ff87,
49: 0x00ffaf,
50: 0x00ffd7,
51: 0x00ffff,
52: 0x5f0000,
53: 0x5f005f,
54: 0x5f0087,
55: 0x5f00af,
56: 0x5f00d7,
57: 0x5f00ff,
58: 0x5f5f00,
59: 0x5f5f5f,
60: 0x5f5f87,
61: 0x5f5faf,
62: 0x5f5fd7,
63: 0x5f5fff,
64: 0x5f8700,
65: 0x5f875f,
66: 0x5f8787,
67: 0x5f87af,
68: 0x5f87d7,
69: 0x5f87ff,
70: 0x5faf00,
71: 0x5faf5f,
72: 0x5faf87,
73: 0x5fafaf,
74: 0x5fafd7,
75: 0x5fafff,
76: 0x5fd700,
77: 0x5fd75f,
78: 0x5fd787,
79: 0x5fd7af,
80: 0x5fd7d7,
81: 0x5fd7ff,
82: 0x5fff00,
83: 0x5fff5f,
84: 0x5fff87,
85: 0x5fffaf,
86: 0x5fffd7,
87: 0x5fffff,
88: 0x870000,
89: 0x87005f,
90: 0x870087,
91: 0x8700af,
92: 0x8700d7,
93: 0x8700ff,
94: 0x875f00,
95: 0x875f5f,
96: 0x875f87,
97: 0x875faf,
98: 0x875fd7,
99: 0x875fff,
100: 0x878700,
101: 0x87875f,
102: 0x878787,
103: 0x8787af,
104: 0x8787d7,
105: 0x8787ff,
106: 0x87af00,
107: 0x87af5f,
108: 0x87af87,
109: 0x87afaf,
110: 0x87afd7,
111: 0x87afff,
112: 0x87d700,
113: 0x87d75f,
114: 0x87d787,
115: 0x87d7af,
116: 0x87d7d7,
117: 0x87d7ff,
118: 0x87ff00,
119: 0x87ff5f,
120: 0x87ff87,
121: 0x87ffaf,
122: 0x87ffd7,
123: 0x87ffff,
124: 0xaf0000,
125: 0xaf005f,
126: 0xaf0087,
127: 0xaf00af,
128: 0xaf00d7,
129: 0xaf00ff,
130: 0xaf5f00,
131: 0xaf5f5f,
132: 0xaf5f87,
133: 0xaf5faf,
134: 0xaf5fd7,
135: 0xaf5fff,
136: 0xaf8700,
137: 0xaf875f,
138: 0xaf8787,
139: 0xaf87af,
140: 0xaf87d7,
141: 0xaf87ff,
142: 0xafaf00,
143: 0xafaf5f,
144: 0xafaf87,
145: 0xafafaf,
146: 0xafafd7,
147: 0xafafff,
148: 0xafd700,
149: 0xafd75f,
150: 0xafd787,
151: 0xafd7af,
152: 0xafd7d7,
153: 0xafd7ff,
154: 0xafff00,
155: 0xafff5f,
156: 0xafff87,
157: 0xafffaf,
158: 0xafffd7,
159: 0xafffff,
160: 0xd70000,
161: 0xd7005f,
162: 0xd70087,
163: 0xd700af,
164: 0xd700d7,
165: 0xd700ff,
166: 0xd75f00,
167: 0xd75f5f,
168: 0xd75f87,
169: 0xd75faf,
170: 0xd75fd7,
171: 0xd75fff,
172: 0xd78700,
173: 0xd7875f,
174: 0xd78787,
175: 0xd787af,
176: 0xd787d7,
177: 0xd787ff,
178: 0xd7af00,
179: 0xd7af5f,
180: 0xd7af87,
181: 0xd7afaf,
182: 0xd7afd7,
183: 0xd7afff,
184: 0xd7d700,
185: 0xd7d75f,
186: 0xd7d787,
187: 0xd7d7af,
188: 0xd7d7d7,
189: 0xd7d7ff,
190: 0xd7ff00,
191: 0xd7ff5f,
192: 0xd7ff87,
193: 0xd7ffaf,
194: 0xd7ffd7,
195: 0xd7ffff,
196: 0xff0000,
197: 0xff005f,
198: 0xff0087,
199: 0xff00af,
200: 0xff00d7,
201: 0xff00ff,
202: 0xff5f00,
203: 0xff5f5f,
204: 0xff5f87,
205: 0xff5faf,
206: 0xff5fd7,
207: 0xff5fff,
208: 0xff8700,
209: 0xff875f,
210: 0xff8787,
211: 0xff87af,
212: 0xff87d7,
213: 0xff87ff,
214: 0xffaf00,
215: 0xffaf5f,
216: 0xffaf87,
217: 0xffafaf,
218: 0xffafd7,
219: 0xffafff,
220: 0xffd700,
221: 0xffd75f,
222: 0xffd787,
223: 0xffd7af,
224: 0xffd7d7,
225: 0xffd7ff,
226: 0xffff00,
227: 0xffff5f,
228: 0xffff87,
229: 0xffffaf,
230: 0xffffd7,
231: 0xffffff,
232: 0x080808,
233: 0x121212,
234: 0x1c1c1c,
235: 0x262626,
236: 0x303030,
237: 0x3a3a3a,
238: 0x444444,
239: 0x4e4e4e,
240: 0x585858,
241: 0x626262,
242: 0x6c6c6c,
243: 0x767676,
244: 0x808080,
245: 0x8a8a8a,
246: 0x949494,
247: 0x9e9e9e,
248: 0xa8a8a8,
249: 0xb2b2b2,
250: 0xbcbcbc,
251: 0xc6c6c6,
252: 0xd0d0d0,
253: 0xdadada,
254: 0xe4e4e4,
255: 0xeeeeee,
}
// `\033]0;TITLESTR\007`
func doTitleSequence(er *bytes.Reader) error {
var c byte
var err error
c, err = er.ReadByte()
if err != nil {
return err
}
if c != '0' && c != '2' {
return nil
}
c, err = er.ReadByte()
if err != nil {
return err
}
if c != ';' {
return nil
}
title := make([]byte, 0, 80)
for {
c, err = er.ReadByte()
if err != nil {
return err
}
if c == 0x07 || c == '\n' {
break
}
title = append(title, c)
}
if len(title) > 0 {
title8, err := syscall.UTF16PtrFromString(string(title))
if err == nil {
procSetConsoleTitle.Call(uintptr(unsafe.Pointer(title8)))
}
}
return nil
}
// Write write data on console
func (w *Writer) Write(data []byte) (n int, err error) {
var csbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
er := bytes.NewReader(data)
var bw [1]byte
loop:
for {
c1, err := er.ReadByte()
if err != nil {
break loop
}
if c1 != 0x1b {
bw[0] = c1
w.out.Write(bw[:])
continue
}
c2, err := er.ReadByte()
if err != nil {
break loop
}
if c2 == ']' {
if err := doTitleSequence(er); err != nil {
break loop
}
continue
}
if c2 != 0x5b {
continue
}
var buf bytes.Buffer
var m byte
for {
c, err := er.ReadByte()
if err != nil {
break loop
}
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
m = c
break
}
buf.Write([]byte(string(c)))
}
switch m {
case 'A':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.y -= short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'B':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.y += short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'C':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x += short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'D':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x -= short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'E':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x = 0
csbi.cursorPosition.y += short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'F':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x = 0
csbi.cursorPosition.y -= short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'G':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x = short(n - 1)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'H', 'f':
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
if buf.Len() > 0 {
token := strings.Split(buf.String(), ";")
switch len(token) {
case 1:
n1, err := strconv.Atoi(token[0])
if err != nil {
continue
}
csbi.cursorPosition.y = short(n1 - 1)
case 2:
n1, err := strconv.Atoi(token[0])
if err != nil {
continue
}
n2, err := strconv.Atoi(token[1])
if err != nil {
continue
}
csbi.cursorPosition.x = short(n2 - 1)
csbi.cursorPosition.y = short(n1 - 1)
}
} else {
csbi.cursorPosition.y = 0
}
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'J':
n := 0
if buf.Len() > 0 {
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
}
var count, written dword
var cursor coord
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
switch n {
case 0:
cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x)
case 1:
cursor = coord{x: csbi.window.left, y: csbi.window.top}
count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.window.top-csbi.cursorPosition.y)*csbi.size.x)
case 2:
cursor = coord{x: csbi.window.left, y: csbi.window.top}
count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x)
}
procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
case 'K':
n := 0
if buf.Len() > 0 {
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
var cursor coord
var count, written dword
switch n {
case 0:
cursor = coord{x: csbi.cursorPosition.x + 1, y: csbi.cursorPosition.y}
count = dword(csbi.size.x - csbi.cursorPosition.x - 1)
case 1:
cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y}
count = dword(csbi.size.x - csbi.cursorPosition.x)
case 2:
cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y}
count = dword(csbi.size.x)
}
procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
case 'm':
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
attr := csbi.attributes
cs := buf.String()
if cs == "" {
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr))
continue
}
token := strings.Split(cs, ";")
for i := 0; i < len(token); i++ {
ns := token[i]
if n, err = strconv.Atoi(ns); err == nil {
switch {
case n == 0 || n == 100:
attr = w.oldattr
case 1 <= n && n <= 5:
attr |= foregroundIntensity
case n == 7:
attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
case n == 22 || n == 25:
attr |= foregroundIntensity
case n == 27:
attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
case 30 <= n && n <= 37:
attr &= backgroundMask
if (n-30)&1 != 0 {
attr |= foregroundRed
}
if (n-30)&2 != 0 {
attr |= foregroundGreen
}
if (n-30)&4 != 0 {
attr |= foregroundBlue
}
case n == 38: // set foreground color.
if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") {
if n256, err := strconv.Atoi(token[i+2]); err == nil {
if n256foreAttr == nil {
n256setup()
}
attr &= backgroundMask
attr |= n256foreAttr[n256]
i += 2
}
} else {
attr = attr & (w.oldattr & backgroundMask)
}
case n == 39: // reset foreground color.
attr &= backgroundMask
attr |= w.oldattr & foregroundMask
case 40 <= n && n <= 47:
attr &= foregroundMask
if (n-40)&1 != 0 {
attr |= backgroundRed
}
if (n-40)&2 != 0 {
attr |= backgroundGreen
}
if (n-40)&4 != 0 {
attr |= backgroundBlue
}
case n == 48: // set background color.
if i < len(token)-2 && token[i+1] == "5" {
if n256, err := strconv.Atoi(token[i+2]); err == nil {
if n256backAttr == nil {
n256setup()
}
attr &= foregroundMask
attr |= n256backAttr[n256]
i += 2
}
} else {
attr = attr & (w.oldattr & foregroundMask)
}
case n == 49: // reset foreground color.
attr &= foregroundMask
attr |= w.oldattr & backgroundMask
case 90 <= n && n <= 97:
attr = (attr & backgroundMask)
attr |= foregroundIntensity
if (n-90)&1 != 0 {
attr |= foregroundRed
}
if (n-90)&2 != 0 {
attr |= foregroundGreen
}
if (n-90)&4 != 0 {
attr |= foregroundBlue
}
case 100 <= n && n <= 107:
attr = (attr & foregroundMask)
attr |= backgroundIntensity
if (n-100)&1 != 0 {
attr |= backgroundRed
}
if (n-100)&2 != 0 {
attr |= backgroundGreen
}
if (n-100)&4 != 0 {
attr |= backgroundBlue
}
}
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr))
}
}
case 'h':
var ci consoleCursorInfo
cs := buf.String()
if cs == "5>" {
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 0
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
} else if cs == "?25" {
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 1
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
}
case 'l':
var ci consoleCursorInfo
cs := buf.String()
if cs == "5>" {
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 1
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
} else if cs == "?25" {
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 0
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
}
case 's':
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
w.oldpos = csbi.cursorPosition
case 'u':
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
}
}
return len(data), nil
}
type consoleColor struct {
rgb int
red bool
green bool
blue bool
intensity bool
}
func (c consoleColor) foregroundAttr() (attr word) {
if c.red {
attr |= foregroundRed
}
if c.green {
attr |= foregroundGreen
}
if c.blue {
attr |= foregroundBlue
}
if c.intensity {
attr |= foregroundIntensity
}
return
}
func (c consoleColor) backgroundAttr() (attr word) {
if c.red {
attr |= backgroundRed
}
if c.green {
attr |= backgroundGreen
}
if c.blue {
attr |= backgroundBlue
}
if c.intensity {
attr |= backgroundIntensity
}
return
}
var color16 = []consoleColor{
{0x000000, false, false, false, false},
{0x000080, false, false, true, false},
{0x008000, false, true, false, false},
{0x008080, false, true, true, false},
{0x800000, true, false, false, false},
{0x800080, true, false, true, false},
{0x808000, true, true, false, false},
{0xc0c0c0, true, true, true, false},
{0x808080, false, false, false, true},
{0x0000ff, false, false, true, true},
{0x00ff00, false, true, false, true},
{0x00ffff, false, true, true, true},
{0xff0000, true, false, false, true},
{0xff00ff, true, false, true, true},
{0xffff00, true, true, false, true},
{0xffffff, true, true, true, true},
}
type hsv struct {
h, s, v float32
}
func (a hsv) dist(b hsv) float32 {
dh := a.h - b.h
switch {
case dh > 0.5:
dh = 1 - dh
case dh < -0.5:
dh = -1 - dh
}
ds := a.s - b.s
dv := a.v - b.v
return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv)))
}
func toHSV(rgb int) hsv {
r, g, b := float32((rgb&0xFF0000)>>16)/256.0,
float32((rgb&0x00FF00)>>8)/256.0,
float32(rgb&0x0000FF)/256.0
min, max := minmax3f(r, g, b)
h := max - min
if h > 0 {
if max == r {
h = (g - b) / h
if h < 0 {
h += 6
}
} else if max == g {
h = 2 + (b-r)/h
} else {
h = 4 + (r-g)/h
}
}
h /= 6.0
s := max - min
if max != 0 {
s /= max
}
v := max
return hsv{h: h, s: s, v: v}
}
type hsvTable []hsv
func toHSVTable(rgbTable []consoleColor) hsvTable {
t := make(hsvTable, len(rgbTable))
for i, c := range rgbTable {
t[i] = toHSV(c.rgb)
}
return t
}
func (t hsvTable) find(rgb int) consoleColor {
hsv := toHSV(rgb)
n := 7
l := float32(5.0)
for i, p := range t {
d := hsv.dist(p)
if d < l {
l, n = d, i
}
}
return color16[n]
}
func minmax3f(a, b, c float32) (min, max float32) {
if a < b {
if b < c {
return a, c
} else if a < c {
return a, b
} else {
return c, b
}
} else {
if a < c {
return b, c
} else if b < c {
return b, a
} else {
return c, a
}
}
}
var n256foreAttr []word
var n256backAttr []word
func n256setup() {
n256foreAttr = make([]word, 256)
n256backAttr = make([]word, 256)
t := toHSVTable(color16)
for i, rgb := range color256 {
c := t.find(rgb)
n256foreAttr[i] = c.foregroundAttr()
n256backAttr[i] = c.backgroundAttr()
}
}

55
vendor/github.com/mattn/go-colorable/noncolorable.go generated vendored Normal file
View File

@ -0,0 +1,55 @@
package colorable
import (
"bytes"
"io"
)
// NonColorable hold writer but remove escape sequence.
type NonColorable struct {
out io.Writer
}
// NewNonColorable return new instance of Writer which remove escape sequence from Writer.
func NewNonColorable(w io.Writer) io.Writer {
return &NonColorable{out: w}
}
// Write write data on console
func (w *NonColorable) Write(data []byte) (n int, err error) {
er := bytes.NewReader(data)
var bw [1]byte
loop:
for {
c1, err := er.ReadByte()
if err != nil {
break loop
}
if c1 != 0x1b {
bw[0] = c1
w.out.Write(bw[:])
continue
}
c2, err := er.ReadByte()
if err != nil {
break loop
}
if c2 != 0x5b {
continue
}
var buf bytes.Buffer
for {
c, err := er.ReadByte()
if err != nil {
break loop
}
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
break
}
buf.Write([]byte(string(c)))
}
}
return len(data), nil
}

9
vendor/github.com/mattn/go-isatty/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,9 @@
language: go
go:
- tip
before_install:
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
script:
- $HOME/gopath/bin/goveralls -repotoken 3gHdORO5k5ziZcWMBxnd9LrMZaJs8m9x5

9
vendor/github.com/mattn/go-isatty/LICENSE generated vendored Normal file
View File

@ -0,0 +1,9 @@
Copyright (c) Yasuhiro MATSUMOTO <mattn.jp@gmail.com>
MIT License (Expat)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

50
vendor/github.com/mattn/go-isatty/README.md generated vendored Normal file
View File

@ -0,0 +1,50 @@
# go-isatty
[![Godoc Reference](https://godoc.org/github.com/mattn/go-isatty?status.svg)](http://godoc.org/github.com/mattn/go-isatty)
[![Build Status](https://travis-ci.org/mattn/go-isatty.svg?branch=master)](https://travis-ci.org/mattn/go-isatty)
[![Coverage Status](https://coveralls.io/repos/github/mattn/go-isatty/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-isatty?branch=master)
[![Go Report Card](https://goreportcard.com/badge/mattn/go-isatty)](https://goreportcard.com/report/mattn/go-isatty)
isatty for golang
## Usage
```go
package main
import (
"fmt"
"github.com/mattn/go-isatty"
"os"
)
func main() {
if isatty.IsTerminal(os.Stdout.Fd()) {
fmt.Println("Is Terminal")
} else if isatty.IsCygwinTerminal(os.Stdout.Fd()) {
fmt.Println("Is Cygwin/MSYS2 Terminal")
} else {
fmt.Println("Is Not Terminal")
}
}
```
## Installation
```
$ go get github.com/mattn/go-isatty
```
## License
MIT
## Author
Yasuhiro Matsumoto (a.k.a mattn)
## Thanks
* k-takata: base idea for IsCygwinTerminal
https://github.com/k-takata/go-iscygpty

2
vendor/github.com/mattn/go-isatty/doc.go generated vendored Normal file
View File

@ -0,0 +1,2 @@
// Package isatty implements interface to isatty
package isatty

15
vendor/github.com/mattn/go-isatty/isatty_appengine.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
// +build appengine
package isatty
// IsTerminal returns true if the file descriptor is terminal which
// is always false on on appengine classic which is a sandboxed PaaS.
func IsTerminal(fd uintptr) bool {
return false
}
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}

18
vendor/github.com/mattn/go-isatty/isatty_bsd.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
// +build darwin freebsd openbsd netbsd dragonfly
// +build !appengine
package isatty
import (
"syscall"
"unsafe"
)
const ioctlReadTermios = syscall.TIOCGETA
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}

18
vendor/github.com/mattn/go-isatty/isatty_linux.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
// +build linux
// +build !appengine,!ppc64,!ppc64le
package isatty
import (
"syscall"
"unsafe"
)
const ioctlReadTermios = syscall.TCGETS
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}

View File

@ -0,0 +1,19 @@
// +build linux
// +build ppc64 ppc64le
package isatty
import (
"unsafe"
syscall "golang.org/x/sys/unix"
)
const ioctlReadTermios = syscall.TCGETS
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}

10
vendor/github.com/mattn/go-isatty/isatty_others.go generated vendored Normal file
View File

@ -0,0 +1,10 @@
// +build !windows
// +build !appengine
package isatty
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}

16
vendor/github.com/mattn/go-isatty/isatty_solaris.go generated vendored Normal file
View File

@ -0,0 +1,16 @@
// +build solaris
// +build !appengine
package isatty
import (
"golang.org/x/sys/unix"
)
// IsTerminal returns true if the given file descriptor is a terminal.
// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
func IsTerminal(fd uintptr) bool {
var termio unix.Termio
err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio)
return err == nil
}

94
vendor/github.com/mattn/go-isatty/isatty_windows.go generated vendored Normal file
View File

@ -0,0 +1,94 @@
// +build windows
// +build !appengine
package isatty
import (
"strings"
"syscall"
"unicode/utf16"
"unsafe"
)
const (
fileNameInfo uintptr = 2
fileTypePipe = 3
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
procGetFileType = kernel32.NewProc("GetFileType")
)
func init() {
// Check if GetFileInformationByHandleEx is available.
if procGetFileInformationByHandleEx.Find() != nil {
procGetFileInformationByHandleEx = nil
}
}
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
}
// Check pipe name is used for cygwin/msys2 pty.
// Cygwin/MSYS2 PTY has a name like:
// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master
func isCygwinPipeName(name string) bool {
token := strings.Split(name, "-")
if len(token) < 5 {
return false
}
if token[0] != `\msys` && token[0] != `\cygwin` {
return false
}
if token[1] == "" {
return false
}
if !strings.HasPrefix(token[2], "pty") {
return false
}
if token[3] != `from` && token[3] != `to` {
return false
}
if token[4] != "master" {
return false
}
return true
}
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
// terminal.
func IsCygwinTerminal(fd uintptr) bool {
if procGetFileInformationByHandleEx == nil {
return false
}
// Cygwin/msys's pty is a pipe.
ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0)
if ft != fileTypePipe || e != 0 {
return false
}
var buf [2 + syscall.MAX_PATH]uint16
r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(),
4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)),
uintptr(len(buf)*2), 0, 0)
if r == 0 || e != 0 {
return false
}
l := *(*uint32)(unsafe.Pointer(&buf))
return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2])))
}

3
vendor/golang.org/x/net/AUTHORS generated vendored Normal file
View File

@ -0,0 +1,3 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.

3
vendor/golang.org/x/net/CONTRIBUTORS generated vendored Normal file
View File

@ -0,0 +1,3 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.

27
vendor/golang.org/x/net/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

22
vendor/golang.org/x/net/PATENTS generated vendored Normal file
View File

@ -0,0 +1,22 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google 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,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

168
vendor/golang.org/x/net/internal/socks/client.go generated vendored Normal file
View File

@ -0,0 +1,168 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package socks
import (
"context"
"errors"
"io"
"net"
"strconv"
"time"
)
var (
noDeadline = time.Time{}
aLongTimeAgo = time.Unix(1, 0)
)
func (d *Dialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) {
host, port, err := splitHostPort(address)
if err != nil {
return nil, err
}
if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
c.SetDeadline(deadline)
defer c.SetDeadline(noDeadline)
}
if ctx != context.Background() {
errCh := make(chan error, 1)
done := make(chan struct{})
defer func() {
close(done)
if ctxErr == nil {
ctxErr = <-errCh
}
}()
go func() {
select {
case <-ctx.Done():
c.SetDeadline(aLongTimeAgo)
errCh <- ctx.Err()
case <-done:
errCh <- nil
}
}()
}
b := make([]byte, 0, 6+len(host)) // the size here is just an estimate
b = append(b, Version5)
if len(d.AuthMethods) == 0 || d.Authenticate == nil {
b = append(b, 1, byte(AuthMethodNotRequired))
} else {
ams := d.AuthMethods
if len(ams) > 255 {
return nil, errors.New("too many authentication methods")
}
b = append(b, byte(len(ams)))
for _, am := range ams {
b = append(b, byte(am))
}
}
if _, ctxErr = c.Write(b); ctxErr != nil {
return
}
if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil {
return
}
if b[0] != Version5 {
return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
}
am := AuthMethod(b[1])
if am == AuthMethodNoAcceptableMethods {
return nil, errors.New("no acceptable authentication methods")
}
if d.Authenticate != nil {
if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil {
return
}
}
b = b[:0]
b = append(b, Version5, byte(d.cmd), 0)
if ip := net.ParseIP(host); ip != nil {
if ip4 := ip.To4(); ip4 != nil {
b = append(b, AddrTypeIPv4)
b = append(b, ip4...)
} else if ip6 := ip.To16(); ip6 != nil {
b = append(b, AddrTypeIPv6)
b = append(b, ip6...)
} else {
return nil, errors.New("unknown address type")
}
} else {
if len(host) > 255 {
return nil, errors.New("FQDN too long")
}
b = append(b, AddrTypeFQDN)
b = append(b, byte(len(host)))
b = append(b, host...)
}
b = append(b, byte(port>>8), byte(port))
if _, ctxErr = c.Write(b); ctxErr != nil {
return
}
if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil {
return
}
if b[0] != Version5 {
return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
}
if cmdErr := Reply(b[1]); cmdErr != StatusSucceeded {
return nil, errors.New("unknown error " + cmdErr.String())
}
if b[2] != 0 {
return nil, errors.New("non-zero reserved field")
}
l := 2
var a Addr
switch b[3] {
case AddrTypeIPv4:
l += net.IPv4len
a.IP = make(net.IP, net.IPv4len)
case AddrTypeIPv6:
l += net.IPv6len
a.IP = make(net.IP, net.IPv6len)
case AddrTypeFQDN:
if _, err := io.ReadFull(c, b[:1]); err != nil {
return nil, err
}
l += int(b[0])
default:
return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3])))
}
if cap(b) < l {
b = make([]byte, l)
} else {
b = b[:l]
}
if _, ctxErr = io.ReadFull(c, b); ctxErr != nil {
return
}
if a.IP != nil {
copy(a.IP, b)
} else {
a.Name = string(b[:len(b)-2])
}
a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1])
return &a, nil
}
func splitHostPort(address string) (string, int, error) {
host, port, err := net.SplitHostPort(address)
if err != nil {
return "", 0, err
}
portnum, err := strconv.Atoi(port)
if err != nil {
return "", 0, err
}
if 1 > portnum || portnum > 0xffff {
return "", 0, errors.New("port number out of range " + port)
}
return host, portnum, nil
}

316
vendor/golang.org/x/net/internal/socks/socks.go generated vendored Normal file
View File

@ -0,0 +1,316 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package socks provides a SOCKS version 5 client implementation.
//
// SOCKS protocol version 5 is defined in RFC 1928.
// Username/Password authentication for SOCKS version 5 is defined in
// RFC 1929.
package socks
import (
"context"
"errors"
"io"
"net"
"strconv"
)
// A Command represents a SOCKS command.
type Command int
func (cmd Command) String() string {
switch cmd {
case CmdConnect:
return "socks connect"
case cmdBind:
return "socks bind"
default:
return "socks " + strconv.Itoa(int(cmd))
}
}
// An AuthMethod represents a SOCKS authentication method.
type AuthMethod int
// A Reply represents a SOCKS command reply code.
type Reply int
func (code Reply) String() string {
switch code {
case StatusSucceeded:
return "succeeded"
case 0x01:
return "general SOCKS server failure"
case 0x02:
return "connection not allowed by ruleset"
case 0x03:
return "network unreachable"
case 0x04:
return "host unreachable"
case 0x05:
return "connection refused"
case 0x06:
return "TTL expired"
case 0x07:
return "command not supported"
case 0x08:
return "address type not supported"
default:
return "unknown code: " + strconv.Itoa(int(code))
}
}
// Wire protocol constants.
const (
Version5 = 0x05
AddrTypeIPv4 = 0x01
AddrTypeFQDN = 0x03
AddrTypeIPv6 = 0x04
CmdConnect Command = 0x01 // establishes an active-open forward proxy connection
cmdBind Command = 0x02 // establishes a passive-open forward proxy connection
AuthMethodNotRequired AuthMethod = 0x00 // no authentication required
AuthMethodUsernamePassword AuthMethod = 0x02 // use username/password
AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods
StatusSucceeded Reply = 0x00
)
// An Addr represents a SOCKS-specific address.
// Either Name or IP is used exclusively.
type Addr struct {
Name string // fully-qualified domain name
IP net.IP
Port int
}
func (a *Addr) Network() string { return "socks" }
func (a *Addr) String() string {
if a == nil {
return "<nil>"
}
port := strconv.Itoa(a.Port)
if a.IP == nil {
return net.JoinHostPort(a.Name, port)
}
return net.JoinHostPort(a.IP.String(), port)
}
// A Conn represents a forward proxy connection.
type Conn struct {
net.Conn
boundAddr net.Addr
}
// BoundAddr returns the address assigned by the proxy server for
// connecting to the command target address from the proxy server.
func (c *Conn) BoundAddr() net.Addr {
if c == nil {
return nil
}
return c.boundAddr
}
// A Dialer holds SOCKS-specific options.
type Dialer struct {
cmd Command // either CmdConnect or cmdBind
proxyNetwork string // network between a proxy server and a client
proxyAddress string // proxy server address
// ProxyDial specifies the optional dial function for
// establishing the transport connection.
ProxyDial func(context.Context, string, string) (net.Conn, error)
// AuthMethods specifies the list of request authention
// methods.
// If empty, SOCKS client requests only AuthMethodNotRequired.
AuthMethods []AuthMethod
// Authenticate specifies the optional authentication
// function. It must be non-nil when AuthMethods is not empty.
// It must return an error when the authentication is failed.
Authenticate func(context.Context, io.ReadWriter, AuthMethod) error
}
// DialContext connects to the provided address on the provided
// network.
//
// The returned error value may be a net.OpError. When the Op field of
// net.OpError contains "socks", the Source field contains a proxy
// server address and the Addr field contains a command target
// address.
//
// See func Dial of the net package of standard library for a
// description of the network and address parameters.
func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
if err := d.validateTarget(network, address); err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
if ctx == nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
}
var err error
var c net.Conn
if d.ProxyDial != nil {
c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress)
} else {
var dd net.Dialer
c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress)
}
if err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
a, err := d.connect(ctx, c, address)
if err != nil {
c.Close()
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
return &Conn{Conn: c, boundAddr: a}, nil
}
// DialWithConn initiates a connection from SOCKS server to the target
// network and address using the connection c that is already
// connected to the SOCKS server.
//
// It returns the connection's local address assigned by the SOCKS
// server.
func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) {
if err := d.validateTarget(network, address); err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
if ctx == nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
}
a, err := d.connect(ctx, c, address)
if err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
return a, nil
}
// Dial connects to the provided address on the provided network.
//
// Unlike DialContext, it returns a raw transport connection instead
// of a forward proxy connection.
//
// Deprecated: Use DialContext or DialWithConn instead.
func (d *Dialer) Dial(network, address string) (net.Conn, error) {
if err := d.validateTarget(network, address); err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
var err error
var c net.Conn
if d.ProxyDial != nil {
c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress)
} else {
c, err = net.Dial(d.proxyNetwork, d.proxyAddress)
}
if err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil {
return nil, err
}
return c, nil
}
func (d *Dialer) validateTarget(network, address string) error {
switch network {
case "tcp", "tcp6", "tcp4":
default:
return errors.New("network not implemented")
}
switch d.cmd {
case CmdConnect, cmdBind:
default:
return errors.New("command not implemented")
}
return nil
}
func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) {
for i, s := range []string{d.proxyAddress, address} {
host, port, err := splitHostPort(s)
if err != nil {
return nil, nil, err
}
a := &Addr{Port: port}
a.IP = net.ParseIP(host)
if a.IP == nil {
a.Name = host
}
if i == 0 {
proxy = a
} else {
dst = a
}
}
return
}
// NewDialer returns a new Dialer that dials through the provided
// proxy server's network and address.
func NewDialer(network, address string) *Dialer {
return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: CmdConnect}
}
const (
authUsernamePasswordVersion = 0x01
authStatusSucceeded = 0x00
)
// UsernamePassword are the credentials for the username/password
// authentication method.
type UsernamePassword struct {
Username string
Password string
}
// Authenticate authenticates a pair of username and password with the
// proxy server.
func (up *UsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth AuthMethod) error {
switch auth {
case AuthMethodNotRequired:
return nil
case AuthMethodUsernamePassword:
if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) == 0 || len(up.Password) > 255 {
return errors.New("invalid username/password")
}
b := []byte{authUsernamePasswordVersion}
b = append(b, byte(len(up.Username)))
b = append(b, up.Username...)
b = append(b, byte(len(up.Password)))
b = append(b, up.Password...)
// TODO(mikio): handle IO deadlines and cancelation if
// necessary
if _, err := rw.Write(b); err != nil {
return err
}
if _, err := io.ReadFull(rw, b[:2]); err != nil {
return err
}
if b[0] != authUsernamePasswordVersion {
return errors.New("invalid username/password version")
}
if b[1] != authStatusSucceeded {
return errors.New("username/password authentication failed")
}
return nil
}
return errors.New("unsupported authentication method " + strconv.Itoa(int(auth)))
}

18
vendor/golang.org/x/net/proxy/direct.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proxy
import (
"net"
)
type direct struct{}
// Direct is a direct proxy: one that makes network connections directly.
var Direct = direct{}
func (direct) Dial(network, addr string) (net.Conn, error) {
return net.Dial(network, addr)
}

140
vendor/golang.org/x/net/proxy/per_host.go generated vendored Normal file
View File

@ -0,0 +1,140 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proxy
import (
"net"
"strings"
)
// A PerHost directs connections to a default Dialer unless the host name
// requested matches one of a number of exceptions.
type PerHost struct {
def, bypass Dialer
bypassNetworks []*net.IPNet
bypassIPs []net.IP
bypassZones []string
bypassHosts []string
}
// NewPerHost returns a PerHost Dialer that directs connections to either
// defaultDialer or bypass, depending on whether the connection matches one of
// the configured rules.
func NewPerHost(defaultDialer, bypass Dialer) *PerHost {
return &PerHost{
def: defaultDialer,
bypass: bypass,
}
}
// Dial connects to the address addr on the given network through either
// defaultDialer or bypass.
func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
return p.dialerForRequest(host).Dial(network, addr)
}
func (p *PerHost) dialerForRequest(host string) Dialer {
if ip := net.ParseIP(host); ip != nil {
for _, net := range p.bypassNetworks {
if net.Contains(ip) {
return p.bypass
}
}
for _, bypassIP := range p.bypassIPs {
if bypassIP.Equal(ip) {
return p.bypass
}
}
return p.def
}
for _, zone := range p.bypassZones {
if strings.HasSuffix(host, zone) {
return p.bypass
}
if host == zone[1:] {
// For a zone ".example.com", we match "example.com"
// too.
return p.bypass
}
}
for _, bypassHost := range p.bypassHosts {
if bypassHost == host {
return p.bypass
}
}
return p.def
}
// AddFromString parses a string that contains comma-separated values
// specifying hosts that should use the bypass proxy. Each value is either an
// IP address, a CIDR range, a zone (*.example.com) or a host name
// (localhost). A best effort is made to parse the string and errors are
// ignored.
func (p *PerHost) AddFromString(s string) {
hosts := strings.Split(s, ",")
for _, host := range hosts {
host = strings.TrimSpace(host)
if len(host) == 0 {
continue
}
if strings.Contains(host, "/") {
// We assume that it's a CIDR address like 127.0.0.0/8
if _, net, err := net.ParseCIDR(host); err == nil {
p.AddNetwork(net)
}
continue
}
if ip := net.ParseIP(host); ip != nil {
p.AddIP(ip)
continue
}
if strings.HasPrefix(host, "*.") {
p.AddZone(host[1:])
continue
}
p.AddHost(host)
}
}
// AddIP specifies an IP address that will use the bypass proxy. Note that
// this will only take effect if a literal IP address is dialed. A connection
// to a named host will never match an IP.
func (p *PerHost) AddIP(ip net.IP) {
p.bypassIPs = append(p.bypassIPs, ip)
}
// AddNetwork specifies an IP range that will use the bypass proxy. Note that
// this will only take effect if a literal IP address is dialed. A connection
// to a named host will never match.
func (p *PerHost) AddNetwork(net *net.IPNet) {
p.bypassNetworks = append(p.bypassNetworks, net)
}
// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
// "example.com" matches "example.com" and all of its subdomains.
func (p *PerHost) AddZone(zone string) {
if strings.HasSuffix(zone, ".") {
zone = zone[:len(zone)-1]
}
if !strings.HasPrefix(zone, ".") {
zone = "." + zone
}
p.bypassZones = append(p.bypassZones, zone)
}
// AddHost specifies a host name that will use the bypass proxy.
func (p *PerHost) AddHost(host string) {
if strings.HasSuffix(host, ".") {
host = host[:len(host)-1]
}
p.bypassHosts = append(p.bypassHosts, host)
}

134
vendor/golang.org/x/net/proxy/proxy.go generated vendored Normal file
View File

@ -0,0 +1,134 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package proxy provides support for a variety of protocols to proxy network
// data.
package proxy // import "golang.org/x/net/proxy"
import (
"errors"
"net"
"net/url"
"os"
"sync"
)
// A Dialer is a means to establish a connection.
type Dialer interface {
// Dial connects to the given address via the proxy.
Dial(network, addr string) (c net.Conn, err error)
}
// Auth contains authentication parameters that specific Dialers may require.
type Auth struct {
User, Password string
}
// FromEnvironment returns the dialer specified by the proxy related variables in
// the environment.
func FromEnvironment() Dialer {
allProxy := allProxyEnv.Get()
if len(allProxy) == 0 {
return Direct
}
proxyURL, err := url.Parse(allProxy)
if err != nil {
return Direct
}
proxy, err := FromURL(proxyURL, Direct)
if err != nil {
return Direct
}
noProxy := noProxyEnv.Get()
if len(noProxy) == 0 {
return proxy
}
perHost := NewPerHost(proxy, Direct)
perHost.AddFromString(noProxy)
return perHost
}
// proxySchemes is a map from URL schemes to a function that creates a Dialer
// from a URL with such a scheme.
var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error)
// RegisterDialerType takes a URL scheme and a function to generate Dialers from
// a URL with that scheme and a forwarding Dialer. Registered schemes are used
// by FromURL.
func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) {
if proxySchemes == nil {
proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error))
}
proxySchemes[scheme] = f
}
// FromURL returns a Dialer given a URL specification and an underlying
// Dialer for it to make network requests.
func FromURL(u *url.URL, forward Dialer) (Dialer, error) {
var auth *Auth
if u.User != nil {
auth = new(Auth)
auth.User = u.User.Username()
if p, ok := u.User.Password(); ok {
auth.Password = p
}
}
switch u.Scheme {
case "socks5":
return SOCKS5("tcp", u.Host, auth, forward)
}
// If the scheme doesn't match any of the built-in schemes, see if it
// was registered by another package.
if proxySchemes != nil {
if f, ok := proxySchemes[u.Scheme]; ok {
return f(u, forward)
}
}
return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
}
var (
allProxyEnv = &envOnce{
names: []string{"ALL_PROXY", "all_proxy"},
}
noProxyEnv = &envOnce{
names: []string{"NO_PROXY", "no_proxy"},
}
)
// envOnce looks up an environment variable (optionally by multiple
// names) once. It mitigates expensive lookups on some platforms
// (e.g. Windows).
// (Borrowed from net/http/transport.go)
type envOnce struct {
names []string
once sync.Once
val string
}
func (e *envOnce) Get() string {
e.once.Do(e.init)
return e.val
}
func (e *envOnce) init() {
for _, n := range e.names {
e.val = os.Getenv(n)
if e.val != "" {
return
}
}
}
// reset is used by tests
func (e *envOnce) reset() {
e.once = sync.Once{}
e.val = ""
}

36
vendor/golang.org/x/net/proxy/socks5.go generated vendored Normal file
View File

@ -0,0 +1,36 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proxy
import (
"context"
"net"
"golang.org/x/net/internal/socks"
)
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given
// address with an optional username and password.
// See RFC 1928 and RFC 1929.
func SOCKS5(network, address string, auth *Auth, forward Dialer) (Dialer, error) {
d := socks.NewDialer(network, address)
if forward != nil {
d.ProxyDial = func(_ context.Context, network string, address string) (net.Conn, error) {
return forward.Dial(network, address)
}
}
if auth != nil {
up := socks.UsernamePassword{
Username: auth.User,
Password: auth.Password,
}
d.AuthMethods = []socks.AuthMethod{
socks.AuthMethodNotRequired,
socks.AuthMethodUsernamePassword,
}
d.Authenticate = up.Authenticate
}
return d, nil
}

3
vendor/golang.org/x/sys/AUTHORS generated vendored Normal file
View File

@ -0,0 +1,3 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.

3
vendor/golang.org/x/sys/CONTRIBUTORS generated vendored Normal file
View File

@ -0,0 +1,3 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.

27
vendor/golang.org/x/sys/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

22
vendor/golang.org/x/sys/PATENTS generated vendored Normal file
View File

@ -0,0 +1,22 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google 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,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

2
vendor/golang.org/x/sys/unix/.gitignore generated vendored Normal file
View File

@ -0,0 +1,2 @@
_obj/
unix.test

173
vendor/golang.org/x/sys/unix/README.md generated vendored Normal file
View File

@ -0,0 +1,173 @@
# Building `sys/unix`
The sys/unix package provides access to the raw system call interface of the
underlying operating system. See: https://godoc.org/golang.org/x/sys/unix
Porting Go to a new architecture/OS combination or adding syscalls, types, or
constants to an existing architecture/OS pair requires some manual effort;
however, there are tools that automate much of the process.
## Build Systems
There are currently two ways we generate the necessary files. We are currently
migrating the build system to use containers so the builds are reproducible.
This is being done on an OS-by-OS basis. Please update this documentation as
components of the build system change.
### Old Build System (currently for `GOOS != "Linux" || GOARCH == "sparc64"`)
The old build system generates the Go files based on the C header files
present on your system. This means that files
for a given GOOS/GOARCH pair must be generated on a system with that OS and
architecture. This also means that the generated code can differ from system
to system, based on differences in the header files.
To avoid this, if you are using the old build system, only generate the Go
files on an installation with unmodified header files. It is also important to
keep track of which version of the OS the files were generated from (ex.
Darwin 14 vs Darwin 15). This makes it easier to track the progress of changes
and have each OS upgrade correspond to a single change.
To build the files for your current OS and architecture, make sure GOOS and
GOARCH are set correctly and run `mkall.sh`. This will generate the files for
your specific system. Running `mkall.sh -n` shows the commands that will be run.
Requirements: bash, perl, go
### New Build System (currently for `GOOS == "Linux" && GOARCH != "sparc64"`)
The new build system uses a Docker container to generate the go files directly
from source checkouts of the kernel and various system libraries. This means
that on any platform that supports Docker, all the files using the new build
system can be generated at once, and generated files will not change based on
what the person running the scripts has installed on their computer.
The OS specific files for the new build system are located in the `${GOOS}`
directory, and the build is coordinated by the `${GOOS}/mkall.go` program. When
the kernel or system library updates, modify the Dockerfile at
`${GOOS}/Dockerfile` to checkout the new release of the source.
To build all the files under the new build system, you must be on an amd64/Linux
system and have your GOOS and GOARCH set accordingly. Running `mkall.sh` will
then generate all of the files for all of the GOOS/GOARCH pairs in the new build
system. Running `mkall.sh -n` shows the commands that will be run.
Requirements: bash, perl, go, docker
## Component files
This section describes the various files used in the code generation process.
It also contains instructions on how to modify these files to add a new
architecture/OS or to add additional syscalls, types, or constants. Note that
if you are using the new build system, the scripts cannot be called normally.
They must be called from within the docker container.
### asm files
The hand-written assembly file at `asm_${GOOS}_${GOARCH}.s` implements system
call dispatch. There are three entry points:
```
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
```
The first and second are the standard ones; they differ only in how many
arguments can be passed to the kernel. The third is for low-level use by the
ForkExec wrapper. Unlike the first two, it does not call into the scheduler to
let it know that a system call is running.
When porting Go to an new architecture/OS, this file must be implemented for
each GOOS/GOARCH pair.
### mksysnum
Mksysnum is a script located at `${GOOS}/mksysnum.pl` (or `mksysnum_${GOOS}.pl`
for the old system). This script takes in a list of header files containing the
syscall number declarations and parses them to produce the corresponding list of
Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated
constants.
Adding new syscall numbers is mostly done by running the build on a sufficiently
new installation of the target OS (or updating the source checkouts for the
new build system). However, depending on the OS, you make need to update the
parsing in mksysnum.
### mksyscall.pl
The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are
hand-written Go files which implement system calls (for unix, the specific OS,
or the specific OS/Architecture pair respectively) that need special handling
and list `//sys` comments giving prototypes for ones that can be generated.
The mksyscall.pl script takes the `//sys` and `//sysnb` comments and converts
them into syscalls. This requires the name of the prototype in the comment to
match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function
prototype can be exported (capitalized) or not.
Adding a new syscall often just requires adding a new `//sys` function prototype
with the desired arguments and a capitalized name so it is exported. However, if
you want the interface to the syscall to be different, often one will make an
unexported `//sys` prototype, an then write a custom wrapper in
`syscall_${GOOS}.go`.
### types files
For each OS, there is a hand-written Go file at `${GOOS}/types.go` (or
`types_${GOOS}.go` on the old system). This file includes standard C headers and
creates Go type aliases to the corresponding C types. The file is then fed
through godef to get the Go compatible definitions. Finally, the generated code
is fed though mkpost.go to format the code correctly and remove any hidden or
private identifiers. This cleaned-up code is written to
`ztypes_${GOOS}_${GOARCH}.go`.
The hardest part about preparing this file is figuring out which headers to
include and which symbols need to be `#define`d to get the actual data
structures that pass through to the kernel system calls. Some C libraries
preset alternate versions for binary compatibility and translate them on the
way in and out of system calls, but there is almost always a `#define` that can
get the real ones.
See `types_darwin.go` and `linux/types.go` for examples.
To add a new type, add in the necessary include statement at the top of the
file (if it is not already there) and add in a type alias line. Note that if
your type is significantly different on different architectures, you may need
some `#if/#elif` macros in your include statements.
### mkerrors.sh
This script is used to generate the system's various constants. This doesn't
just include the error numbers and error strings, but also the signal numbers
an a wide variety of miscellaneous constants. The constants come from the list
of include files in the `includes_${uname}` variable. A regex then picks out
the desired `#define` statements, and generates the corresponding Go constants.
The error numbers and strings are generated from `#include <errno.h>`, and the
signal numbers and strings are generated from `#include <signal.h>`. All of
these constants are written to `zerrors_${GOOS}_${GOARCH}.go` via a C program,
`_errors.c`, which prints out all the constants.
To add a constant, add the header that includes it to the appropriate variable.
Then, edit the regex (if necessary) to match the desired constant. Avoid making
the regex too broad to avoid matching unintended constants.
## Generated files
### `zerror_${GOOS}_${GOARCH}.go`
A file containing all of the system's generated error numbers, error strings,
signal numbers, and constants. Generated by `mkerrors.sh` (see above).
### `zsyscall_${GOOS}_${GOARCH}.go`
A file containing all the generated syscalls for a specific GOOS and GOARCH.
Generated by `mksyscall.pl` (see above).
### `zsysnum_${GOOS}_${GOARCH}.go`
A list of numeric constants for all the syscall number of the specific GOOS
and GOARCH. Generated by mksysnum (see above).
### `ztypes_${GOOS}_${GOARCH}.go`
A file containing Go types for passing into (or returning from) syscalls.
Generated by godefs and the types file (see above).

124
vendor/golang.org/x/sys/unix/affinity_linux.go generated vendored Normal file
View File

@ -0,0 +1,124 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// CPU affinity functions
package unix
import (
"unsafe"
)
const cpuSetSize = _CPU_SETSIZE / _NCPUBITS
// CPUSet represents a CPU affinity mask.
type CPUSet [cpuSetSize]cpuMask
func schedAffinity(trap uintptr, pid int, set *CPUSet) error {
_, _, e := RawSyscall(trap, uintptr(pid), uintptr(unsafe.Sizeof(*set)), uintptr(unsafe.Pointer(set)))
if e != 0 {
return errnoErr(e)
}
return nil
}
// SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
// If pid is 0 the calling thread is used.
func SchedGetaffinity(pid int, set *CPUSet) error {
return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set)
}
// SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
// If pid is 0 the calling thread is used.
func SchedSetaffinity(pid int, set *CPUSet) error {
return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set)
}
// Zero clears the set s, so that it contains no CPUs.
func (s *CPUSet) Zero() {
for i := range s {
s[i] = 0
}
}
func cpuBitsIndex(cpu int) int {
return cpu / _NCPUBITS
}
func cpuBitsMask(cpu int) cpuMask {
return cpuMask(1 << (uint(cpu) % _NCPUBITS))
}
// Set adds cpu to the set s.
func (s *CPUSet) Set(cpu int) {
i := cpuBitsIndex(cpu)
if i < len(s) {
s[i] |= cpuBitsMask(cpu)
}
}
// Clear removes cpu from the set s.
func (s *CPUSet) Clear(cpu int) {
i := cpuBitsIndex(cpu)
if i < len(s) {
s[i] &^= cpuBitsMask(cpu)
}
}
// IsSet reports whether cpu is in the set s.
func (s *CPUSet) IsSet(cpu int) bool {
i := cpuBitsIndex(cpu)
if i < len(s) {
return s[i]&cpuBitsMask(cpu) != 0
}
return false
}
// Count returns the number of CPUs in the set s.
func (s *CPUSet) Count() int {
c := 0
for _, b := range s {
c += onesCount64(uint64(b))
}
return c
}
// onesCount64 is a copy of Go 1.9's math/bits.OnesCount64.
// Once this package can require Go 1.9, we can delete this
// and update the caller to use bits.OnesCount64.
func onesCount64(x uint64) int {
const m0 = 0x5555555555555555 // 01010101 ...
const m1 = 0x3333333333333333 // 00110011 ...
const m2 = 0x0f0f0f0f0f0f0f0f // 00001111 ...
const m3 = 0x00ff00ff00ff00ff // etc.
const m4 = 0x0000ffff0000ffff
// Implementation: Parallel summing of adjacent bits.
// See "Hacker's Delight", Chap. 5: Counting Bits.
// The following pattern shows the general approach:
//
// x = x>>1&(m0&m) + x&(m0&m)
// x = x>>2&(m1&m) + x&(m1&m)
// x = x>>4&(m2&m) + x&(m2&m)
// x = x>>8&(m3&m) + x&(m3&m)
// x = x>>16&(m4&m) + x&(m4&m)
// x = x>>32&(m5&m) + x&(m5&m)
// return int(x)
//
// Masking (& operations) can be left away when there's no
// danger that a field's sum will carry over into the next
// field: Since the result cannot be > 64, 8 bits is enough
// and we can ignore the masks for the shifts by 8 and up.
// Per "Hacker's Delight", the first line can be simplified
// more, but it saves at best one instruction, so we leave
// it alone for clarity.
const m = 1<<64 - 1
x = x>>1&(m0&m) + x&(m0&m)
x = x>>2&(m1&m) + x&(m1&m)
x = (x>>4 + x) & (m2 & m)
x += x >> 8
x += x >> 16
x += x >> 32
return int(x) & (1<<7 - 1)
}

14
vendor/golang.org/x/sys/unix/aliases.go generated vendored Normal file
View File

@ -0,0 +1,14 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
// +build go1.9
package unix
import "syscall"
type Signal = syscall.Signal
type Errno = syscall.Errno
type SysProcAttr = syscall.SysProcAttr

29
vendor/golang.org/x/sys/unix/asm_darwin_386.s generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
#include "textflag.h"
//
// System call support for 386, Darwin
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)

29
vendor/golang.org/x/sys/unix/asm_darwin_amd64.s generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
#include "textflag.h"
//
// System call support for AMD64, Darwin
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

30
vendor/golang.org/x/sys/unix/asm_darwin_arm.s generated vendored Normal file
View File

@ -0,0 +1,30 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
// +build arm,darwin
#include "textflag.h"
//
// System call support for ARM, Darwin
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
B syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
B syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
B syscall·RawSyscall6(SB)

30
vendor/golang.org/x/sys/unix/asm_darwin_arm64.s generated vendored Normal file
View File

@ -0,0 +1,30 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
// +build arm64,darwin
#include "textflag.h"
//
// System call support for AMD64, Darwin
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
B syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
B syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
B syscall·RawSyscall6(SB)

29
vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
#include "textflag.h"
//
// System call support for AMD64, DragonFly
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

29
vendor/golang.org/x/sys/unix/asm_freebsd_386.s generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
#include "textflag.h"
//
// System call support for 386, FreeBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)

29
vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
#include "textflag.h"
//
// System call support for AMD64, FreeBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

29
vendor/golang.org/x/sys/unix/asm_freebsd_arm.s generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
#include "textflag.h"
//
// System call support for ARM, FreeBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
B syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
B syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
B syscall·RawSyscall6(SB)

65
vendor/golang.org/x/sys/unix/asm_linux_386.s generated vendored Normal file
View File

@ -0,0 +1,65 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
#include "textflag.h"
//
// System calls for 386, Linux
//
// See ../runtime/sys_linux_386.s for the reason why we always use int 0x80
// instead of the glibc-specific "CALL 0x10(GS)".
#define INVOKE_SYSCALL INT $0x80
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
CALL runtime·entersyscall(SB)
MOVL trap+0(FP), AX // syscall entry
MOVL a1+4(FP), BX
MOVL a2+8(FP), CX
MOVL a3+12(FP), DX
MOVL $0, SI
MOVL $0, DI
INVOKE_SYSCALL
MOVL AX, r1+16(FP)
MOVL DX, r2+20(FP)
CALL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
MOVL trap+0(FP), AX // syscall entry
MOVL a1+4(FP), BX
MOVL a2+8(FP), CX
MOVL a3+12(FP), DX
MOVL $0, SI
MOVL $0, DI
INVOKE_SYSCALL
MOVL AX, r1+16(FP)
MOVL DX, r2+20(FP)
RET
TEXT ·socketcall(SB),NOSPLIT,$0-36
JMP syscall·socketcall(SB)
TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
JMP syscall·rawsocketcall(SB)
TEXT ·seek(SB),NOSPLIT,$0-28
JMP syscall·seek(SB)

57
vendor/golang.org/x/sys/unix/asm_linux_amd64.s generated vendored Normal file
View File

@ -0,0 +1,57 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
#include "textflag.h"
//
// System calls for AMD64, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
CALL runtime·entersyscall(SB)
MOVQ a1+8(FP), DI
MOVQ a2+16(FP), SI
MOVQ a3+24(FP), DX
MOVQ $0, R10
MOVQ $0, R8
MOVQ $0, R9
MOVQ trap+0(FP), AX // syscall entry
SYSCALL
MOVQ AX, r1+32(FP)
MOVQ DX, r2+40(FP)
CALL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVQ a1+8(FP), DI
MOVQ a2+16(FP), SI
MOVQ a3+24(FP), DX
MOVQ $0, R10
MOVQ $0, R8
MOVQ $0, R9
MOVQ trap+0(FP), AX // syscall entry
SYSCALL
MOVQ AX, r1+32(FP)
MOVQ DX, r2+40(FP)
RET
TEXT ·gettimeofday(SB),NOSPLIT,$0-16
JMP syscall·gettimeofday(SB)

56
vendor/golang.org/x/sys/unix/asm_linux_arm.s generated vendored Normal file
View File

@ -0,0 +1,56 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
#include "textflag.h"
//
// System calls for arm, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
B syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
BL runtime·entersyscall(SB)
MOVW trap+0(FP), R7
MOVW a1+4(FP), R0
MOVW a2+8(FP), R1
MOVW a3+12(FP), R2
MOVW $0, R3
MOVW $0, R4
MOVW $0, R5
SWI $0
MOVW R0, r1+16(FP)
MOVW $0, R0
MOVW R0, r2+20(FP)
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
B syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
MOVW trap+0(FP), R7 // syscall entry
MOVW a1+4(FP), R0
MOVW a2+8(FP), R1
MOVW a3+12(FP), R2
SWI $0
MOVW R0, r1+16(FP)
MOVW $0, R0
MOVW R0, r2+20(FP)
RET
TEXT ·seek(SB),NOSPLIT,$0-28
B syscall·seek(SB)

52
vendor/golang.org/x/sys/unix/asm_linux_arm64.s generated vendored Normal file
View File

@ -0,0 +1,52 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux
// +build arm64
// +build !gccgo
#include "textflag.h"
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
B syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R0
MOVD a2+16(FP), R1
MOVD a3+24(FP), R2
MOVD $0, R3
MOVD $0, R4
MOVD $0, R5
MOVD trap+0(FP), R8 // syscall entry
SVC
MOVD R0, r1+32(FP) // r1
MOVD R1, r2+40(FP) // r2
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
B syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVD a1+8(FP), R0
MOVD a2+16(FP), R1
MOVD a3+24(FP), R2
MOVD $0, R3
MOVD $0, R4
MOVD $0, R5
MOVD trap+0(FP), R8 // syscall entry
SVC
MOVD R0, r1+32(FP)
MOVD R1, r2+40(FP)
RET

56
vendor/golang.org/x/sys/unix/asm_linux_mips64x.s generated vendored Normal file
View File

@ -0,0 +1,56 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux
// +build mips64 mips64le
// +build !gccgo
#include "textflag.h"
//
// System calls for mips64, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
JAL runtime·entersyscall(SB)
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV R0, R7
MOVV R0, R8
MOVV R0, R9
MOVV trap+0(FP), R2 // syscall entry
SYSCALL
MOVV R2, r1+32(FP)
MOVV R3, r2+40(FP)
JAL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV R0, R7
MOVV R0, R8
MOVV R0, R9
MOVV trap+0(FP), R2 // syscall entry
SYSCALL
MOVV R2, r1+32(FP)
MOVV R3, r2+40(FP)
RET

54
vendor/golang.org/x/sys/unix/asm_linux_mipsx.s generated vendored Normal file
View File

@ -0,0 +1,54 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux
// +build mips mipsle
// +build !gccgo
#include "textflag.h"
//
// System calls for mips, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
JAL runtime·entersyscall(SB)
MOVW a1+4(FP), R4
MOVW a2+8(FP), R5
MOVW a3+12(FP), R6
MOVW R0, R7
MOVW trap+0(FP), R2 // syscall entry
SYSCALL
MOVW R2, r1+16(FP) // r1
MOVW R3, r2+20(FP) // r2
JAL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
MOVW a1+4(FP), R4
MOVW a2+8(FP), R5
MOVW a3+12(FP), R6
MOVW trap+0(FP), R2 // syscall entry
SYSCALL
MOVW R2, r1+16(FP)
MOVW R3, r2+20(FP)
RET

56
vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s generated vendored Normal file
View File

@ -0,0 +1,56 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux
// +build ppc64 ppc64le
// +build !gccgo
#include "textflag.h"
//
// System calls for ppc64, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
BR syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
BR syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R3
MOVD a2+16(FP), R4
MOVD a3+24(FP), R5
MOVD R0, R6
MOVD R0, R7
MOVD R0, R8
MOVD trap+0(FP), R9 // syscall entry
SYSCALL R9
MOVD R3, r1+32(FP)
MOVD R4, r2+40(FP)
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
BR syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
BR syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVD a1+8(FP), R3
MOVD a2+16(FP), R4
MOVD a3+24(FP), R5
MOVD R0, R6
MOVD R0, R7
MOVD R0, R8
MOVD trap+0(FP), R9 // syscall entry
SYSCALL R9
MOVD R3, r1+32(FP)
MOVD R4, r2+40(FP)
RET

56
vendor/golang.org/x/sys/unix/asm_linux_s390x.s generated vendored Normal file
View File

@ -0,0 +1,56 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build s390x
// +build linux
// +build !gccgo
#include "textflag.h"
//
// System calls for s390x, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
BR syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
BR syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R2
MOVD a2+16(FP), R3
MOVD a3+24(FP), R4
MOVD $0, R5
MOVD $0, R6
MOVD $0, R7
MOVD trap+0(FP), R1 // syscall entry
SYSCALL
MOVD R2, r1+32(FP)
MOVD R3, r2+40(FP)
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
BR syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
BR syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVD a1+8(FP), R2
MOVD a2+16(FP), R3
MOVD a3+24(FP), R4
MOVD $0, R5
MOVD $0, R6
MOVD $0, R7
MOVD trap+0(FP), R1 // syscall entry
SYSCALL
MOVD R2, r1+32(FP)
MOVD R3, r2+40(FP)
RET

29
vendor/golang.org/x/sys/unix/asm_netbsd_386.s generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
#include "textflag.h"
//
// System call support for 386, NetBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)

Some files were not shown because too many files have changed in this diff Show More