2020-04-02 14:07:56 +00:00
package adlin
import (
2022-04-20 18:11:38 +00:00
"context"
2021-03-25 13:38:20 +00:00
"crypto/ed25519"
2020-04-02 14:07:56 +00:00
"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"
)
2021-03-03 17:44:26 +00:00
const StdNetmask = 80
2021-03-25 13:38:20 +00:00
var (
collector_secret ed25519 . PrivateKey
)
func SetCollectorSecret ( b [ ] byte ) {
collector_secret = ed25519 . NewKeyFromSeed ( b )
}
func GetCollectorPublic ( ) ed25519 . PublicKey {
return collector_secret . Public ( ) . ( ed25519 . PublicKey )
}
2022-04-30 00:41:12 +00:00
func StudentIP ( idstd int64 , overrideid int ) net . IP {
return net . ParseIP ( fmt . Sprintf ( "2a01:e0a:2b:2252:%x%x::" , overrideid , idstd ) )
2020-04-02 14:07:56 +00:00
}
2022-04-30 00:41:12 +00:00
func StudentNet ( idstd int64 , overrideid int ) * net . IPNet {
2021-03-03 17:44:26 +00:00
return & net . IPNet {
2022-04-30 00:41:12 +00:00
IP : StudentIP ( idstd , overrideid ) ,
2021-03-03 17:44:26 +00:00
Mask : net . CIDRMask ( StdNetmask , 128 ) ,
}
}
2020-04-02 14:07:56 +00:00
type WGDump struct {
PubKey string
PSK string
Endpoint string
AllowedIPs string
LastHandS string
RX string
TX string
KeepAlive string
}
2021-03-25 13:38:20 +00:00
func ( d * WGDump ) GetPubKey ( ) ( [ ] byte , error ) {
return base64 . StdEncoding . DecodeString ( d . PubKey )
}
2020-04-02 14:36:29 +00:00
var (
2021-03-07 11:39:38 +00:00
wgDumpCache_data map [ string ] * WGDump = nil
2020-04-02 14:36:29 +00:00
wgDumpCache_time time . Time
wgDumpCache_mutex sync . RWMutex
)
2021-03-07 11:39:38 +00:00
func _readWgDump ( ) ( wgd map [ string ] * WGDump , err error ) {
2022-04-20 18:11:38 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , 500 * time . Millisecond )
defer cancel ( )
2020-04-02 14:07:56 +00:00
2022-04-20 18:11:38 +00:00
out , err := exec . CommandContext ( ctx , "wg" , "show" , "wg-adlin" , "dump" ) . Output ( )
if err != nil {
return nil , err
2020-04-02 14:07:56 +00:00
}
2021-03-07 11:39:38 +00:00
wgd = map [ string ] * WGDump { }
2020-04-02 14:07:56 +00:00
for _ , line := range strings . Split ( string ( out ) , "\n" ) {
cols := strings . Fields ( line )
if len ( cols ) != 8 {
continue
}
2021-03-07 11:39:38 +00:00
wgd [ cols [ 0 ] ] = & WGDump { cols [ 0 ] , cols [ 1 ] , cols [ 2 ] , cols [ 3 ] , cols [ 4 ] , cols [ 5 ] , cols [ 6 ] , cols [ 7 ] }
2020-04-02 14:07:56 +00:00
}
return
}
2021-03-07 11:39:38 +00:00
func readWgDump ( ) ( wgd map [ string ] * WGDump , err error ) {
2020-04-02 14:36:29 +00:00
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 ( )
}
2022-04-20 18:11:38 +00:00
return
2020-04-02 14:36:29 +00:00
}
2020-04-02 14:07:56 +00:00
type TunnelToken struct {
2022-04-30 00:41:12 +00:00
token [ ] byte
TokenText string
IdStudent int64
PubKey [ ] byte
Time time . Time
SuffixIP int
OverrideID int
2020-04-02 14:07:56 +00:00
// Version stores the TP number where the token is used
Version int
Dump * WGDump
}
2021-03-04 00:05:24 +00:00
func ( tt * TunnelToken ) GetStudentIP ( ) string {
2021-03-04 00:32:09 +00:00
if tt . SuffixIP == 0 {
2022-04-30 00:41:12 +00:00
return fmt . Sprintf ( "%s%x" , StudentIP ( tt . IdStudent , tt . OverrideID ) . String ( ) , 1 )
2021-03-04 00:32:09 +00:00
} else {
2022-04-30 00:41:12 +00:00
return fmt . Sprintf ( "%s%x" , StudentIP ( tt . IdStudent , tt . OverrideID ) . String ( ) , tt . SuffixIP )
2021-03-04 00:32:09 +00:00
}
2021-03-04 00:05:24 +00:00
}
2022-04-29 20:34:12 +00:00
func ( tt * TunnelToken ) GetServerIP ( suffix int ) string {
2022-04-30 00:41:12 +00:00
return fmt . Sprintf ( "%s%x" , StudentIP ( tt . IdStudent , tt . OverrideID ) . String ( ) , suffix )
2022-04-29 20:34:12 +00:00
}
2021-03-25 13:38:20 +00:00
func ( tt * TunnelToken ) GenKeySign ( ) [ ] byte {
stdprivkey := ed25519 . NewKeyFromSeed ( tt . token [ : ed25519 . SeedSize ] )
stdpublic := [ ] byte ( stdprivkey . Public ( ) . ( ed25519 . PublicKey ) )
return ed25519 . Sign ( collector_secret , stdpublic )
}
2021-03-02 18:08:42 +00:00
func TokenFromText ( token string ) [ ] byte {
2020-04-02 14:07:56 +00:00
sha := sha512 . Sum512 ( [ ] byte ( token ) )
return sha [ : ]
}
2021-03-07 11:39:38 +00:00
func GetTunnelToken ( token [ ] byte ) ( t * TunnelToken , err error ) {
t = new ( TunnelToken )
2022-04-30 00:41:12 +00:00
err = DBQueryRow ( "SELECT token, token_text, id_student, pubkey, time, suffixip, idoverride, 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 . OverrideID , & t . Version )
2020-04-02 14:07:56 +00:00
if err == nil && t . PubKey != nil {
if wgd , errr := readWgDump ( ) ; errr == nil {
if v , ok := wgd [ base64 . StdEncoding . EncodeToString ( t . PubKey ) ] ; ok {
2021-03-07 11:39:38 +00:00
t . Dump = v
2020-04-02 14:07:56 +00:00
}
}
}
return
}
2021-03-07 11:39:38 +00:00
func ( student * Student ) NewTunnelToken ( suffixip int ) ( t * TunnelToken , err error ) {
2020-04-02 14:07:56 +00:00
tok := make ( [ ] byte , 7 )
if _ , err = rand . Read ( tok ) ; err != nil {
return
}
2021-03-07 11:39:38 +00:00
t = new ( TunnelToken )
2021-03-04 00:05:46 +00:00
t . TokenText = strings . Replace ( strings . Replace ( strings . Replace ( strings . Replace ( strings . Replace ( base64 . RawStdEncoding . EncodeToString ( tok ) , "/" , "." , - 1 ) , "+" , "_" , - 1 ) , "O" , "<" , - 1 ) , "l" , "$" , - 1 ) , "I" , ">" , - 1 )
2021-03-02 18:08:42 +00:00
t . token = TokenFromText ( t . TokenText )
2020-04-02 14:07:56 +00:00
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
}
2021-03-07 11:39:38 +00:00
func ( student * Student ) GetTunnelTokens ( ) ( ts [ ] * TunnelToken , err error ) {
2022-04-30 00:41:12 +00:00
if rows , errr := DBQuery ( "SELECT token, token_text, id_student, pubkey, time, suffixip, idoverride, version FROM student_tunnel_tokens WHERE id_student = ? ORDER BY time DESC" , student . Id ) ; errr != nil {
2020-04-02 14:07:56 +00:00
return nil , errr
} else if wgd , errr := readWgDump ( ) ; errr != nil {
return nil , errr
} else {
defer rows . Close ( )
for rows . Next ( ) {
2021-03-07 11:39:38 +00:00
t := & TunnelToken { }
2022-04-30 00:41:12 +00:00
if err = rows . Scan ( & t . token , & t . TokenText , & t . IdStudent , & t . PubKey , & t . Time , & t . SuffixIP , & t . OverrideID , & t . Version ) ; err != nil {
2020-04-02 14:07:56 +00:00
return
}
if t . PubKey != nil {
if v , ok := wgd [ base64 . StdEncoding . EncodeToString ( t . PubKey ) ] ; ok {
2021-03-07 11:39:38 +00:00
t . Dump = v
2020-04-02 14:07:56 +00:00
}
}
ts = append ( ts , t )
}
if err = rows . Err ( ) ; err != nil {
return
}
return
}
}
2021-03-07 11:39:38 +00:00
func ( student * Student ) GetActivesTunnels ( ) ( ts [ ] * TunnelToken , err error ) {
2022-04-30 00:41:12 +00:00
if rows , errr := DBQuery ( "SELECT token, token_text, id_student, pubkey, time, suffixip, idoverride, version FROM student_tunnel_tokens WHERE id_student = ? ORDER BY time DESC" , student . Id ) ; errr != nil {
2021-02-04 08:39:23 +00:00
return nil , errr
} else if wgd , errr := readWgDump ( ) ; errr != nil {
return nil , errr
} else {
defer rows . Close ( )
for rows . Next ( ) {
2021-03-07 11:39:38 +00:00
t := & TunnelToken { }
2022-04-30 00:41:12 +00:00
if err = rows . Scan ( & t . token , & t . TokenText , & t . IdStudent , & t . PubKey , & t . Time , & t . SuffixIP , & t . OverrideID , & t . Version ) ; err != nil {
2021-02-04 08:39:23 +00:00
return
}
if t . PubKey != nil {
if v , ok := wgd [ base64 . StdEncoding . EncodeToString ( t . PubKey ) ] ; ok {
2021-03-07 11:39:38 +00:00
t . Dump = v
2021-02-04 08:39:23 +00:00
ts = append ( ts , t )
}
}
}
if err = rows . Err ( ) ; err != nil {
return
}
return
}
}
2022-03-10 18:40:02 +00:00
func ( student * Student ) GetDefaultTunnels ( ) ( ts [ ] * TunnelToken , err error ) {
t := & TunnelToken { IdStudent : student . Id }
ts = append ( ts , t )
return
}
2021-03-25 13:38:20 +00:00
func ( student * Student ) GetActivesTunnelsPubKey ( ) ( ts [ ] ed25519 . PublicKey , err error ) {
var activeTuns [ ] * TunnelToken
activeTuns , err = student . GetActivesTunnels ( )
if err != nil {
return
}
for _ , tun := range activeTuns {
if tun . Dump != nil {
pk := ed25519 . NewKeyFromSeed ( tun . token [ : ed25519 . SeedSize ] )
ts = append ( ts , pk . Public ( ) . ( ed25519 . PublicKey ) )
}
}
return
}
2021-03-07 11:39:38 +00:00
func ( student * Student ) GetTunnelToken ( token [ ] byte ) ( t * TunnelToken , err error ) {
t = new ( TunnelToken )
2022-04-30 00:41:12 +00:00
err = DBQueryRow ( "SELECT token, token_text, id_student, pubkey, time, suffixip, idoverride, 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 . OverrideID , & t . Version )
2020-04-02 14:07:56 +00:00
if err == nil && t . PubKey != nil {
if wgd , errr := readWgDump ( ) ; errr == nil {
if v , ok := wgd [ base64 . StdEncoding . EncodeToString ( t . PubKey ) ] ; ok {
2021-03-07 11:39:38 +00:00
t . Dump = v
2020-04-02 14:07:56 +00:00
}
}
}
return
}
func ( t * TunnelToken ) Update ( ) ( int64 , error ) {
2021-03-02 18:08:42 +00:00
newtoken := TokenFromText ( t . TokenText )
2020-04-02 14:07:56 +00:00
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
}
}
2021-03-02 18:08:42 +00:00
func ( t * TunnelToken ) Delete ( ) ( int64 , error ) {
if res , err := DBExec ( "DELETE FROM student_tunnel_tokens WHERE token = ? AND id_student = ?" , t . token , t . IdStudent ) ; err != nil {
return 0 , err
} else if nb , err := res . RowsAffected ( ) ; err != nil {
return 0 , err
} else {
return nb , err
}
}
2021-03-07 11:39:38 +00:00
func GetStudentsTunnels ( ) ( ts [ ] * TunnelToken , err error ) {
2022-04-30 00:41:12 +00:00
if rows , errr := DBQuery ( "SELECT T.token, T.token_text, T.id_student, T.pubkey, T.time, T.suffixip, T.idoverride, T.version FROM student_tunnel_tokens T INNER JOIN (SELECT B.id_student, MAX(B.time) AS time, B.idoverride FROM student_tunnel_tokens B WHERE B.pubkey IS NOT NULL GROUP BY id_student, idoverride) L ON T.id_student = L.id_student AND T.time = L.time" ) ; errr != nil {
2020-04-02 14:07:56 +00:00
return nil , errr
} else {
defer rows . Close ( )
for rows . Next ( ) {
2021-03-07 11:39:38 +00:00
t := & TunnelToken { }
2022-04-30 00:41:12 +00:00
if err = rows . Scan ( & t . token , & t . TokenText , & t . IdStudent , & t . PubKey , & t . Time , & t . SuffixIP , & t . OverrideID , & t . Version ) ; err != nil {
2020-04-02 14:07:56 +00:00
return
}
ts = append ( ts , t )
}
err = rows . Err ( )
return
}
}