11package main
22
33import (
4+ "net"
45 "os"
6+ "os/exec"
57 "os/signal"
8+ "strings"
69 "syscall"
710 "time"
811
12+ "github.com/google/shlex"
913 "github.com/spf13/cobra"
1014
1115 "github.com/hzyitc/mnh/TCPMode"
4751 service string
4852
4953 upnpD bool
54+
55+ eventHook string
5056)
5157
5258func commonCmdRegister (cmd * cobra.Command ) {
@@ -58,6 +64,8 @@ func commonCmdRegister(cmd *cobra.Command) {
5864 cmd .PersistentFlags ().StringVarP (& service , "service" , "t" , "127.0.0.1:80" , "Target service address. Only need in proxy mode" )
5965
6066 cmd .PersistentFlags ().BoolVarP (& upnpD , "disable-upnp" , "u" , false , "Disable UPnP" )
67+
68+ cmd .PersistentFlags ().StringVarP (& eventHook , "event-hook" , "x" , "" , "Execute command when event triggered" )
6169}
6270
6371func tcpCmdRegister (cmd * cobra.Command ) {
@@ -74,6 +82,34 @@ func udpCmdRegister(cmd *cobra.Command) {
7482 cmd .AddCommand (udpCmd )
7583}
7684
85+ func runHook (event string , errmsg string , port string , addr string ) {
86+ if eventHook == "" {
87+ return
88+ }
89+
90+ cmdline := strings .NewReplacer (
91+ "%%" , "%" ,
92+ "%e" , event ,
93+ "%m" , errmsg ,
94+ "%p" , port ,
95+ "%a" , addr ,
96+ ).Replace (eventHook )
97+ log .Debug ("Running hook:" , cmdline )
98+
99+ args , err := shlex .Split (cmdline )
100+ if err != nil {
101+ log .Error ("Split hook error:" , err .Error ())
102+ return
103+ }
104+
105+ cmd := exec .Command (args [0 ], args [1 :]... )
106+ err = cmd .Start ()
107+ if err != nil {
108+ log .Error ("Run hook error:" , err .Error ())
109+ return
110+ }
111+ }
112+
77113func main () {
78114 tcpCmdRegister (rootCmd )
79115 udpCmdRegister (rootCmd )
@@ -122,9 +158,12 @@ func tcp() {
122158
123159 for {
124160 func () {
161+ runHook ("connecting" , "" , "" , "" )
162+
125163 protocol , err := TCPProtocol .NewMnhv1 (mode , server , id )
126164 if err != nil {
127165 log .Error ("NewMnhv1 error:" , err .Error ())
166+ runHook ("fail" , err .Error (), "" , "" )
128167 return
129168 }
130169 defer protocol .Close ()
@@ -136,6 +175,11 @@ func tcp() {
136175
137176 log .Info ("\n \n Now you can use " + protocol .RemoteHoleAddr ().String () + " to access your service" )
138177
178+ _ , port , _ := net .SplitHostPort (protocol .LocalHoleAddr ().String ())
179+ addr := protocol .RemoteHoleAddr ().String ()
180+ runHook ("success" , "" , port , addr )
181+ defer runHook ("disconnected" , "" , port , addr )
182+
139183 select {
140184 case <- protocol .ClosedChan ():
141185 return
@@ -193,9 +237,12 @@ func udp() {
193237
194238 for {
195239 func () {
240+ runHook ("connecting" , "" , "" , "" )
241+
196242 protocol , err := UDPProtocol .NewMnhv1 (mode , server , id )
197243 if err != nil {
198244 log .Error ("NewMnhv1 error:" , err .Error ())
245+ runHook ("fail" , err .Error (), "" , "" )
199246 return
200247 }
201248 defer protocol .Close ()
@@ -207,6 +254,11 @@ func udp() {
207254
208255 log .Info ("\n \n Now you can use " + protocol .RemoteHoleAddr ().String () + " to access your service" )
209256
257+ _ , port , _ := net .SplitHostPort (protocol .LocalHoleAddr ().String ())
258+ addr := protocol .RemoteHoleAddr ().String ()
259+ runHook ("success" , "" , port , addr )
260+ defer runHook ("disconnected" , "" , port , addr )
261+
210262 select {
211263 case <- protocol .ClosedChan ():
212264 return
0 commit comments