Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
glnds committed Feb 14, 2016
0 parents commit 5bc0af0
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.json
*.log
dyndns_route53
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM centos:centos7
MAINTAINER Gert Leenders <[email protected]>




67 changes: 67 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# DynDNS Route53

This is a little program written in [Go](https://golang.org/project/) that
takes the WAN ip of your current infrastructure to update a hostname hosted
on [Amazon Route53](https://aws.amazon.com/route53/).

## Installation

### Make a binary
One of the main reasons to choose Go to develop this program was the fact
that Go can build executable binaries, which makes installation very easy. Secondly
with Go it's also very easy to cross compile the program for different platforms.

To make a binary just run:
```
go build dyndns_route53.go
```
This will result in an executable binary named `dyndns_route53`.

#### Cross compile
This real power however is that you can cross compile the code for a number of
platforms.
Personally I have this program running on my (Synology) NAS.
This NAS is running Linux and has a x86-64 architecture. In order to
get the program running on that device you need to cross compile it for that specific platform.
To achieve this, you have to specify two extra parameters on the build command:
`GOOS` and `GOARCH`, you can find the appropriate values for
these variables [here](https://golang.org/doc/install/source#environment).

Here's how I build an executable binary for my NAS:
```
# env GOOS=linux GOARCH=amd64 go build dyndns_route53.go
```

### Configuration
Put a file named `config.json` in the same directory as you executable. A file named `config.example` is included in the repository to make your life easy. It looks like this:
```
{
"aws_access_key_id": "ABC...",
"aws_secret_access_key: "XYZ...",
"hosted_zone_id": "A1..",
"fqdn": "www.example.com"
}
```

### Logging
The program will write its output to a file named `dyndns.log` under the same directory as you executable.

## Usage

Test and run locally:
```
go build dyndns_route53.go
go run dyndns_route53.go
```

## Contributing

1. Fork it!
2. Create your feature branch: `git checkout -b my-new-feature`
3. Commit your changes: `git commit -am 'Add some feature'`
4. Push to the branch: `git push origin my-new-feature`
5. Submit a pull request :D

## License

MIT: http://rem.mit-license.org
6 changes: 6 additions & 0 deletions config.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"aws_access_key_id": "ABC...",
"aws_secret_access_key: "XYZ...",
"hosted_zone_id": "A1..",
"fqdn": "www.example.com"
}
121 changes: 121 additions & 0 deletions dyndns_route53.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package main

import (
"encoding/json"
"net"
"net/http"
"os"
"path"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/route53"
"github.com/kardianos/osext"

"github.com/op/go-logging"
)

var log = logging.MustGetLogger("dyndns")
var format = logging.MustStringFormatter(`%{time:2006-01-02T15:04:05.999999999} %{shortfunc} - %{level:.5s} %{message}`)

type Configuration struct {
AwsAccessKeyId string
AwsSecretAccessKey string
HostedZoneId string
Fqdn string
}

type Response struct {
Ip string
}

func perror(err error, logger *logging.Logger) {
if err != nil {
logger.Error(err.Error())
panic(err)
}
}

func main() {
// Get the current directory
dir, err := osext.ExecutableFolder()
perror(err, log)

// Initialze a log file
logFile, err := os.OpenFile(path.Join(dir, "dyndns.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
loggingBackend := logging.NewLogBackend(logFile, "", 0)
backendFormatter := logging.NewBackendFormatter(loggingBackend, format)
backendLeveled := logging.AddModuleLevel(backendFormatter)
backendLeveled.SetLevel(logging.INFO, "")
logging.SetBackend(backendLeveled)
perror(err, log)

// Read the config file
configFile, err := os.Open(path.Join(dir, "config.json"))
perror(err, log)
decoder := json.NewDecoder(configFile)
var config Configuration
err = decoder.Decode(&config)
perror(err, log)

// Request your WAN ip
url := "https://api.ipify.org?format=json"
res, err := http.Get(url)
perror(err, log)
defer res.Body.Close()
decoder = json.NewDecoder(res.Body)
var body Response
err = decoder.Decode(&body)
perror(err, log)
wanIp := body.Ip
log.Debugf("Current WAN ip: %s", wanIp)

// Obtain the current ip bounded to the FQDN
ips, err := net.LookupHost(config.Fqdn)
currentIp := ips[0]
log.Debugf("Current ip bounded to '%s': %s", config.Fqdn, currentIp)

// Update the FQDN's ip in case the current WAN ip is different from the ip bounded to the FQDN
if currentIp != wanIp {

log.Infof("'%s' out-of-date update '%s' to '%s'", config.Fqdn, currentIp, wanIp)

var token string
creds := credentials.NewStaticCredentials(config.AwsAccessKeyId, config.AwsSecretAccessKey, token)

svc := route53.New(session.New(), &aws.Config{
Credentials: creds,
})

params := &route53.ChangeResourceRecordSetsInput{
ChangeBatch: &route53.ChangeBatch{ // Required
Changes: []*route53.Change{ // Required
{ // Required
Action: aws.String("UPSERT"), // Required
ResourceRecordSet: &route53.ResourceRecordSet{ // Required
Name: aws.String("synology.pixxis.be"), // Required
Type: aws.String("A"), // Required
ResourceRecords: []*route53.ResourceRecord{
{ // Required
Value: aws.String(body.Ip), // Required
},
},
TTL: aws.Int64(111),
},
},
},
Comment: aws.String("IP update by GO script"),
},
HostedZoneId: aws.String(config.HostedZoneId), // Required
}
resp, err := svc.ChangeResourceRecordSets(params)
perror(err, log)

// Pretty-print the response data.
log.Debug(resp)

} else {
log.Infof("'%s' is up-to-date", config.Fqdn)
}
}

0 comments on commit 5bc0af0

Please sign in to comment.