Skip to content

Commit

Permalink
Add command line option: -b, -bind-ip. With this option, you can bind…
Browse files Browse the repository at this point in the history
… one or more IP addresses to the ran web server.
  • Loading branch information
m3ng9i committed Jun 24, 2020
1 parent 6c35aa6 commit 843abd7
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 77 deletions.
15 changes: 14 additions & 1 deletion global/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const DefaultTLSPolicy = TLSOnly

// Setting about ran server
type Setting struct {
IP []string // IP addresses binded to ran server.
Port uint // HTTP port. Default is 8080.
ShowConf bool // If show config info in the log.
Debug bool // If turns on debug mode. Default is false.
Expand Down Expand Up @@ -264,6 +265,9 @@ Usage: ran [Options...]
Options:
-r, -root=<path> Root path of the site. Default is current working directory.
-b, -bind-ip=<ip> Bind one or more IP addresses to the ran web server.
Multiple IP addresses should be separated by comma.
If not provide this Option, ran will use 0.0.0.0.
-p, -port=<port> HTTP port. Default is 8080.
-404=<path> Path of a custom 404 file, relative to Root. Example: /404.html.
-i, -index=<path> File name of index, priority depends on the order of values.
Expand Down Expand Up @@ -338,7 +342,7 @@ func LoadConfig(versionInfo string) {
os.Exit(1)
}

var configPath, root, path404, authMethod, auth, path401, certPath, keyPath, tlsPolicy string
var configPath, bindip, root, path404, authMethod, auth, path401, certPath, keyPath, tlsPolicy string
var port, tlsPort uint
var indexName server.Index
var version, help, makeCert bool
Expand All @@ -350,6 +354,8 @@ func LoadConfig(versionInfo string) {
// TODO: load config file
}

flag.StringVar(&bindip, "b", "", "IP addresses binded to ran server")
flag.StringVar(&bindip, "bind-ip", "", "IP addresses binded to ran server")
flag.UintVar( &port, "p", 0, "HTTP port")
flag.UintVar( &port, "port", 0, "HTTP port")
flag.StringVar(&root, "r", "", "Root path of the website")
Expand Down Expand Up @@ -428,6 +434,12 @@ func LoadConfig(versionInfo string) {
}
}

Config.IP, err = getIPs(bindip)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %s\n", err)
os.Exit(1)
}

if port > 0 {
Config.Port = port
}
Expand Down Expand Up @@ -480,3 +492,4 @@ func LoadConfig(versionInfo string) {
return
}


124 changes: 124 additions & 0 deletions global/ip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package global

import (
"net"
"strings"
"fmt"
)


// Get network interface index by it's IP.
// Usage example: getInterfaceIndexByIP(net.ParseIP("fe80::aaaa:bbbb:cccc:dddd"))
func getInterfaceIndexByIP(addr net.IP) (index int, e error) {
if addr == nil {
e = fmt.Errorf("IP address is not correct")
return
}

iface, err := net.Interfaces()
if e != nil {
e = err
return
}

for _, i := range iface {
addrs, err := i.Addrs()
if err != nil {
e = err
return
}

for _, a := range addrs {
address := net.ParseIP(strings.SplitN(a.String(), "/", 2)[0])
if addr.Equal(address) {
index = i.Index
return
}
}
}

e = fmt.Errorf("Could not found interface by this IP address: '%s'", addr.String())

return
}


// check if an address is IPv6 link local address (fe80::/10)
func isIPv6LinkLocalAddress(addr net.IP) bool {
if addr.To4() != nil {
return false
}
return addr.IsLinkLocalUnicast()
}


// get all IPs from command-line option -bind-ip
func getIPs(bindIP string) (ips []string, err error) {
anyIP := []string{"0.0.0.0"}

if bindIP == "" {
ips = anyIP
return
}

var invalidIPs []string
allIPs := make(map[string]interface{})

for _, item := range strings.Split(bindIP, ",") {
item = strings.TrimSpace(item)
if item == "" {
continue
}
add := net.ParseIP(item)
if add != nil {
if add.To4() != nil {
// IPv4 address
allIPs[add.String()] = nil
} else {
// IPv6 address

if isIPv6LinkLocalAddress(add) {
// if the address is an IPv6 link local address (fe80::/10),
// add a scope (interface index) to the end of the address.
index, e := getInterfaceIndexByIP(add)
if e != nil {
err = e
return
}
allIPs[fmt.Sprintf("[%s%%%d]", add.String(), index)] = nil
} else {
allIPs[fmt.Sprintf("[%s]", add.String())] = nil
}
}
} else {
invalidIPs = append(invalidIPs, item)
}
}

if len(invalidIPs) > 0 {
err = fmt.Errorf("Invalid IP: %s", strings.Join(invalidIPs, ", "))
return
}


if _, ok := allIPs["0.0.0.0"]; ok {
ips = anyIP
return
}
if _, ok := allIPs["[::]"]; ok {
ips = anyIP
return
}

for key, _ := range allIPs {
ips = append(ips, key)
}

if len(ips) == 0 {
err = fmt.Errorf("No IP address provided")
return
}

return
}

128 changes: 52 additions & 76 deletions ran.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import "syscall"
import "os/signal"
import "net"
import "net/http"
import "os"
import "fmt"
Expand Down Expand Up @@ -35,62 +34,26 @@ func catchSignal() {
}



// Get all available IPv4 addresses in system's network interface.
func getIPAutomaticly() (ip []string, e error) {
iface, err := net.Interfaces()
if err != nil {
e = err
return
}

for _, i := range iface {
addrs, err := i.Addrs()
if e != nil {
e = err
return
}
for _, a := range addrs {
add := net.ParseIP(strings.SplitN(a.String(), "/", 2)[0])
if add.To4() != nil {
ip = append(ip, add.String())
}
}
}

for _, i := range ip {
if i == "127.0.0.1" {
return
}
}

// add loopback
ip = append(ip, "127.0.0.1")

return
}


// Get all Listening address, like: http://127.0.0.1:8080
// Get all Listening address, like: http://127.0.0.1:8080. The return value is used for recording logs.
func getListeningAddr() (addr []string, err error) {
ips, err := getIPAutomaticly()
if err != nil {
return
}

for _, i := range ips {
for _, ip := range global.Config.IP {
if global.Config.TLS != nil {
if global.Config.TLS.Policy == global.TLSOnly {
addr = append(addr, fmt.Sprintf("https://%s:%d", i, global.Config.TLS.Port))
addr = append(addr, fmt.Sprintf("https://%s:%d", ip, global.Config.TLS.Port))
} else {
addr = append(addr, fmt.Sprintf("http://%s:%d", i, global.Config.Port))
addr = append(addr, fmt.Sprintf("https://%s:%d", i, global.Config.TLS.Port))
addr = append(addr, fmt.Sprintf("http://%s:%d", ip, global.Config.Port))
addr = append(addr, fmt.Sprintf("https://%s:%d", ip, global.Config.TLS.Port))
}
} else {
addr = append(addr, fmt.Sprintf("http://%s:%d", i, global.Config.Port))
addr = append(addr, fmt.Sprintf("http://%s:%d", ip, global.Config.Port))
}
}

if len(addr) == 0 {
err = fmt.Errorf("No IP address provided")
return
}

return
}

Expand Down Expand Up @@ -132,7 +95,6 @@ func startLog() {


func main() {

global.LoadConfig(versionInfo)

defer func() {
Expand All @@ -158,39 +120,53 @@ func main() {
ran := server.NewRanServer(global.Config.Config, global.Logger)

startHTTPServer := func() {
wg.Add(1)
go func() {
err := http.ListenAndServe(fmt.Sprintf(":%d", global.Config.Port), ran.Serve())
if err != nil {
global.Logger.Fatal(err)
}
wg.Done()
}()
for _, ip := range global.Config.IP {
wg.Add(1)
go func(ip string) {
err := http.ListenAndServe(
fmt.Sprintf("%s:%d", ip, global.Config.Port),
ran.Serve(),
)
if err != nil {
global.Logger.Fatal(err)
}
wg.Done()
}(ip)
}
}

startTLSServer := func() {
wg.Add(1)
go func() {
err := http.ListenAndServeTLS(fmt.Sprintf(":%d", global.Config.TLS.Port),
global.Config.TLS.PublicKey,
global.Config.TLS.PrivateKey,
ran.Serve())
if err != nil {
global.Logger.Fatal(err)
}
wg.Done()
}()
for _, ip := range global.Config.IP {
wg.Add(1)
go func(ip string) {
err := http.ListenAndServeTLS(
fmt.Sprintf("%s:%d", ip, global.Config.TLS.Port),
global.Config.TLS.PublicKey,
global.Config.TLS.PrivateKey,
ran.Serve(),
)
if err != nil {
global.Logger.Fatal(err)
}
wg.Done()
}(ip)
}
}

redirectToHTTPS := func() {
wg.Add(1)
go func() {
err := http.ListenAndServe(fmt.Sprintf(":%d", global.Config.Port), ran.RedirectToHTTPS(global.Config.TLS.Port))
if err != nil {
global.Logger.Fatal(err)
}
wg.Done()
}()
for _, ip := range global.Config.IP {
wg.Add(1)
go func(ip string) {
err := http.ListenAndServe(
fmt.Sprintf("%s:%d", ip, global.Config.Port),
ran.RedirectToHTTPS(global.Config.TLS.Port),
)
if err != nil {
global.Logger.Fatal(err)
}
wg.Done()
}(ip)
}
}

if global.Config.TLS != nil {
Expand Down

0 comments on commit 843abd7

Please sign in to comment.