2020-04-02 14:07:56 +00:00
package adlin
import (
"crypto/rand"
"crypto/sha512"
"encoding/base64"
"fmt"
"net"
"os/exec"
"strings"
2020-04-02 14:36:29 +00:00
"sync"
2020-04-02 14:07:56 +00:00
"time"
)
func StudentIP ( idstd int64 ) net . IP {
return net . ParseIP ( fmt . Sprintf ( "2a01:e0a:2b:2252:%x::" , idstd ) )
}
type WGDump struct {
PubKey string
PSK string
Endpoint string
AllowedIPs string
LastHandS string
RX string
TX string
KeepAlive string
}
2020-04-02 14:36:29 +00:00
var (
wgDumpCache_data map [ string ] WGDump = nil
wgDumpCache_time time . Time
wgDumpCache_mutex sync . RWMutex
)
func _readWgDump ( ) ( wgd map [ string ] WGDump , err error ) {
2020-04-02 14:07:56 +00:00
out , errr := exec . Command ( "wg" , "show" , "wg-adlin" , "dump" ) . Output ( )
if errr != nil {
return nil , errr
}
wgd = map [ string ] WGDump { }
for _ , line := range strings . Split ( string ( out ) , "\n" ) {
cols := strings . Fields ( line )
if len ( cols ) != 8 {
continue
}
wgd [ cols [ 0 ] ] = WGDump { cols [ 0 ] , cols [ 1 ] , cols [ 2 ] , cols [ 3 ] , cols [ 4 ] , cols [ 5 ] , cols [ 6 ] , cols [ 7 ] }
}
return
}
2020-04-02 14:36:29 +00:00
func readWgDump ( ) ( wgd map [ string ] WGDump , err error ) {
wgDumpCache_mutex . RLock ( )
defer wgDumpCache_mutex . RUnlock ( )
wgd = wgDumpCache_data
if time . Since ( wgDumpCache_time ) > time . Second * 10 {
wgDumpCache_mutex . RUnlock ( )
wgDumpCache_mutex . Lock ( )
if time . Since ( wgDumpCache_time ) > time . Second * 10 {
wgd , err = _readWgDump ( )
if err != nil {
2020-04-25 21:51:47 +00:00
wgDumpCache_mutex . Unlock ( )
wgDumpCache_mutex . RLock ( )
2020-04-02 14:36:29 +00:00
return
}
wgDumpCache_data = wgd
wgDumpCache_time = time . Now ( )
}
wgDumpCache_mutex . Unlock ( )
wgDumpCache_mutex . RLock ( )
}
return wgd , nil
}
2020-04-02 14:07:56 +00:00
type TunnelToken struct {
token [ ] byte
TokenText string
IdStudent int64
PubKey [ ] byte
Time time . Time
SuffixIP int
// Version stores the TP number where the token is used
Version int
Dump * WGDump
}
func tokenFromText ( token string ) [ ] byte {
sha := sha512 . Sum512 ( [ ] byte ( token ) )
return sha [ : ]
}
func GetTunnelToken ( token [ ] byte ) ( t TunnelToken , err error ) {
err = DBQueryRow ( "SELECT token, token_text, id_student, pubkey, time, suffixip, version FROM student_tunnel_tokens WHERE token=? ORDER BY time DESC" , token ) . Scan ( & t . token , & t . TokenText , & t . IdStudent , & t . PubKey , & t . Time , & t . SuffixIP , & t . Version )
if err == nil && t . PubKey != nil {
if wgd , errr := readWgDump ( ) ; errr == nil {
if v , ok := wgd [ base64 . StdEncoding . EncodeToString ( t . PubKey ) ] ; ok {
t . Dump = & v
}
}
}
return
}
func ( student Student ) NewTunnelToken ( suffixip int ) ( t TunnelToken , err error ) {
tok := make ( [ ] byte , 7 )
if _ , err = rand . Read ( tok ) ; err != nil {
return
}
t . TokenText = strings . Replace ( strings . Replace ( strings . Replace ( strings . Replace ( strings . Replace ( base64 . RawStdEncoding . EncodeToString ( tok ) , "/" , "." , - 1 ) , "+" , "_" , - 1 ) , "O" , "#" , - 1 ) , "l" , "$" , - 1 ) , "I" , ">" , - 1 )
t . token = tokenFromText ( t . TokenText )
t . IdStudent = student . Id
_ , err = DBExec ( "INSERT INTO student_tunnel_tokens (token, token_text, id_student, time, suffixip, version) VALUES (?, ?, ?, ?, ?, 0)" , t . token , t . TokenText , student . Id , time . Now ( ) , suffixip )
return
}
func ( student Student ) GetTunnelTokens ( ) ( ts [ ] TunnelToken , err error ) {
if rows , errr := DBQuery ( "SELECT token, token_text, id_student, pubkey, time, suffixip, version FROM student_tunnel_tokens WHERE id_student = ? ORDER BY time DESC" , student . Id ) ; errr != nil {
return nil , errr
} else if wgd , errr := readWgDump ( ) ; errr != nil {
return nil , errr
} else {
defer rows . Close ( )
for rows . Next ( ) {
var t TunnelToken
if err = rows . Scan ( & t . token , & t . TokenText , & t . IdStudent , & t . PubKey , & t . Time , & t . SuffixIP , & t . Version ) ; err != nil {
return
}
if t . PubKey != nil {
if v , ok := wgd [ base64 . StdEncoding . EncodeToString ( t . PubKey ) ] ; ok {
t . Dump = & v
}
}
ts = append ( ts , t )
}
if err = rows . Err ( ) ; err != nil {
return
}
return
}
}
2021-02-04 08:39:23 +00:00
func ( student Student ) GetActivesTunnels ( ) ( ts [ ] TunnelToken , err error ) {
if rows , errr := DBQuery ( "SELECT token, token_text, id_student, pubkey, time, suffixip, version FROM student_tunnel_tokens WHERE id_student = ? ORDER BY time DESC" , student . Id ) ; errr != nil {
return nil , errr
} else if wgd , errr := readWgDump ( ) ; errr != nil {
return nil , errr
} else {
defer rows . Close ( )
for rows . Next ( ) {
var t TunnelToken
if err = rows . Scan ( & t . token , & t . TokenText , & t . IdStudent , & t . PubKey , & t . Time , & t . SuffixIP , & t . Version ) ; err != nil {
return
}
if t . PubKey != nil {
if v , ok := wgd [ base64 . StdEncoding . EncodeToString ( t . PubKey ) ] ; ok {
t . Dump = & v
ts = append ( ts , t )
}
}
}
if err = rows . Err ( ) ; err != nil {
return
}
return
}
}
2020-04-02 14:07:56 +00:00
func ( student Student ) GetTunnelToken ( token [ ] byte ) ( t TunnelToken , err error ) {
err = DBQueryRow ( "SELECT token, token_text, id_student, pubkey, time, suffixip, version FROM student_tunnel_tokens WHERE token = ? AND id_student = ? ORDER BY time DESC" , token , student . Id ) . Scan ( & t . token , & t . TokenText , & t . IdStudent , & t . PubKey , & t . Time , & t . SuffixIP , & t . Version )
if err == nil && t . PubKey != nil {
if wgd , errr := readWgDump ( ) ; errr == nil {
if v , ok := wgd [ base64 . StdEncoding . EncodeToString ( t . PubKey ) ] ; ok {
t . Dump = & v
}
}
}
return
}
func ( t * TunnelToken ) Update ( ) ( int64 , error ) {
newtoken := tokenFromText ( t . TokenText )
tm := time . Now ( )
if res , err := DBExec ( "UPDATE student_tunnel_tokens SET token = ?, token_text = ?, id_student = ?, pubkey = ?, time = ?, suffixip = ?, version = ? WHERE token = ?" , newtoken , t . TokenText , t . IdStudent , t . PubKey , tm , t . SuffixIP , t . Version , t . token ) ; err != nil {
return 0 , err
} else if nb , err := res . RowsAffected ( ) ; err != nil {
return 0 , err
} else {
t . token = newtoken
t . Time = tm
return nb , err
}
}
func GetStudentsTunnels ( ) ( ts [ ] TunnelToken , err error ) {
if rows , errr := DBQuery ( "SELECT T.token, T.token_text, T.id_student, T.pubkey, T.time, T.suffixip, T.version FROM student_tunnel_tokens T INNER JOIN (SELECT B.id_student, MAX(B.time) AS time FROM student_tunnel_tokens B WHERE B.pubkey IS NOT NULL GROUP BY id_student) L ON T.id_student = L.id_student AND T.time = L.time" ) ; errr != nil {
return nil , errr
} else {
defer rows . Close ( )
for rows . Next ( ) {
var t TunnelToken
if err = rows . Scan ( & t . token , & t . TokenText , & t . IdStudent , & t . PubKey , & t . Time , & t . SuffixIP , & t . Version ) ; err != nil {
return
}
ts = append ( ts , t )
}
err = rows . Err ( )
return
}
}