Telegram Bot Webhook - Connection Refused (Golang) - apache

I have configured a Telegram bot to use Webhooks according to the following configuration:
OS: Ubuntu
Server: Apache2
Virtual Host:
Sucessfully linked to domain
Listening on port 8843
Ports 443, 8843 all open with ufw allow
Webhook:
Set to "domain.app:8843/" bot.Token
HandleFunc set to "/" + bot.Token
certFile and keyFile are used succesfully with ListenAndServeTLS
Still, however, my bot just won't work, spend literally the entire last 18 hours trying to fix it. It is 3 at night now, and I just am at my wits end.
When I start my binary it prints the following to stdout:
2023/01/07 01:50:15 Authorized on account ExampleAccount
2023/01/07 01:50:15 setWebhook resp:
{"ok":true,"result":true,"description":"Webhook is already set"}
2023/01/07 01:50:15 getWebhookInfo resp:
{"ok":true,"result":{"url":"https://domain.app:8443/MY_BOT_TOKEN","has_custom_certificate":false,"pending_update_count":0,"last_error_date":1673052633,"last_error_message":"Connection
refused","max_connections":40,"ip_address":"x.x.x.x"}}
2023/01/07 01:50:15 Telegram callback failed: Connection refused
If somebody has any idea please help me!
2023/01/07 02:07:57 getWebhookInfo resp:
{"ok":true,"result":{"url":"https://domain.app:8443/MY_BOT_TOKEN","has_custom_certificate":false,"pending_update_count":3,"last_error_date":1673052633,"last_error_message":"Connection
refused","max_connections":40,"ip_address":"167.99.34.89"}}
If I issue start commands to the bot, the pending_update_count actually gets incremented as well, so this is a really strange issue.
My code:
func main() {
// Create a new bot
bot, err := tgbotapi.NewBotAPI("PLACEHOLDER")
if err != nil {
log.Panic(err)
}
bot.Debug = true
log.Printf("Authorized on account %s", bot.Self.UserName)
// Set the webhook
_, err = bot.SetWebhook(tgbotapi.NewWebhook("https://domain.app:8443/" + bot.Token))
if err != nil {
log.Panic(err)
}
info, err := bot.GetWebhookInfo()
if err != nil {
log.Fatal(err)
}
if info.LastErrorDate != 0 {
log.Printf("Telegram callback failed: %s", info.LastErrorMessage)
}
// Start the webhook server
http.HandleFunc("/"+bot.Token, func(w http.ResponseWriter, r *http.Request) {
update := tgbotapi.Update{}
err := json.NewDecoder(r.Body).Decode(&update)
if err != nil {
log.Println(err)
return
}
// Check if the update is a callback query (button press)
if update.CallbackQuery != nil {
callbackQuery := update.CallbackQuery
data := callbackQuery.Data
// Create a new message
msg := tgbotapi.NewMessage(callbackQuery.Message.Chat.ID, "")
// Set the text and keyboard based on the button pressed
switch data {
case "get_information":
msg.Text = "Here is some information about which formats are supported:"
msg.ReplyMarkup = tgbotapi.NewRemoveKeyboard(true)
case "start_file_conversion":
msg.Text = "Great! Click the link to download your file: https://example.com/ks283dj"
msg.ReplyMarkup = tgbotapi.NewRemoveKeyboard(true)
}
// Send the message
bot.Send(msg)
}
})
log.Printf("About to listen on 0.0.0.0:8443:8443")
errServe := http.ListenAndServeTLS("0.0.0.0:8443", "fullchain.pem", "privkey.pem", nil)
log.Fatal(errServe)
}

The Webhook setup is wrong here:
Instead of:
_, err = bot.SetWebhook(tgbotapi.NewWebhook("https://domain.app:8443/" + bot.Token))
http.HandleFunc("/"+bot.Token, func(w http.ResponseWriter, r *http.Request)
Use:
_, err = bot.SetWebhook(tgbotapi.NewWebhook("https://domain.app:8443/bot" + bot.Token))
http.HandleFunc("/bot"+bot.Token, func(w http.ResponseWriter, r *http.Request)
As described here: https://core.telegram.org/bots/api:
All queries to the Telegram Bot API must be served over HTTPS and need
to be presented in this form:
https://api.telegram.org/bot/METHOD_NAME.

Related

How to calculate resources sizing to prevent a golang http server to reach OS resources limits

I have a simple golang rest application that answer to an echo request like this:
// Return echo message
func echoHandler(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
message := params["message"]
fmt.Fprintf(w, "%s", message)
}
func main() {
// Config data
port := ":9596"
router := mux.NewRouter() //.StrictSlash(true)
router.HandleFunc("/echo/{message}", echoHandler).Methods("GET")
srv := &http.Server{
Addr: port,
// Good practice to set timeouts to avoid Slowloris attacks.
// Using just the read parameter due to this article
// https://stackoverflow.com/questions/29334407/creating-an-idle-timeout-in-go
//WriteTimeout: time.Second * 60,
ReadTimeout: time.Second * 15,
////: time.Second * 120,
//Handler: router,
Handler: router,
}
// Run our server in a goroutine so that it doesn't block.
go func() {
log.Println("Running server....")
//log.Fatal(http.ListenAndServe(port, router))
//log.Println(s.ListenAndServe())
if err := srv.ListenAndServe(); err != nil {
log.Println(err)
}
}()
c := make(chan os.Signal, 1)
// We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C)
// SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught.
signal.Notify(c, os.Interrupt)
// Block until we receive our signal.
<-c
// Create a deadline to wait for.
ctx, cancel := context.WithTimeout(context.Background(), wait)
defer cancel()
// Doesn't block if no connections, but will otherwise wait
// until the timeout deadline.
srv.Shutdown(ctx)
// Optionally, you could run srv.Shutdown in a goroutine and block on
// <-ctx.Done() if your application should wait for other services
// to finalize based on context cancellation.
fmt.Println("\n\n")
log.Println("shutting down")
log.Println("Goddbye!....")
os.Exit(0)
}
This program is called by another service through a GET request:
// Return default message for root routing
func Index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
}
// Handle iterative path and calls iterative calculation service
func echoHandler(calledServiceURL string) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
url := calledServiceURL + "/echo/" + params["message"]
tr := &http.Transport{
//MaxIdleConns: 500,
//MaxIdleConnsPerHost: 500,
}
netClient := &http.Client{Transport: tr}
req, reqErr := http.NewRequest("GET", url, nil)
if reqErr != nil {
log.Fatal("Error en response: ", reqErr)
fmt.Fprintf(w, "Error en response: %s", reqErr)
return
}
//req.Header.Set("Connection", "close")
//req.Header.Set("Connection", "Keep-Alive")
//resp, err := netClient.Get(url)
resp, err := netClient.Do(req)
if err != nil {
log.Fatal("Error en response: ", err)
fmt.Fprintf(w, "Error en response: %s", err)
return
}
respData, errResp := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if errResp != nil {
log.Fatal("Error en RespData", errResp)
fmt.Fprintf(w, "Error en respData: %s", err)
return
}
fmt.Fprintf(w, "%s", respData)
}
}
// Main function
func main() {
// Set default values
port := ":9296"
calledServiceURL := "http://localhost:9596"
router := mux.NewRouter() //.StrictSlash(true)
router.HandleFunc("/", Index).Methods("GET")
router.HandleFunc("/echo/{message}", echoHandler(calledServiceURL)).Methods("GET")
srv := &http.Server{
Addr: port,
// Good practice to set timeouts to avoid Slowloris attacks.
// Using just the read parameter due to this article
// https://stackoverflow.com/questions/29334407/creating-an-idle-timeout-in-go
//WriteTimeout: time.Second * 60,
ReadTimeout: time.Second * 15,
//IdleTimeout: time.Second * 120,
//Handler: router, // Pass our instance of gorilla/mux in.
Handler: router,
}
// Run our server in a goroutine so that it doesn't block.
go func() {
log.Println("Running server....")
if err := srv.ListenAndServe(); err != nil {
log.Println(err)
}
}()
c := make(chan os.Signal, 1)
// We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C)
// SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught.
signal.Notify(c, os.Interrupt)
// Block until we receive our signal.
<-c
// Create a deadline to wait for.
ctx, cancel := context.WithTimeout(context.Background(), wait)
defer cancel()
// Doesn't block if no connections, but will otherwise wait
// until the timeout deadline.
srv.Shutdown(ctx)
// Optionally, you could run srv.Shutdown in a goroutine and block on
// <-ctx.Done() if your application should wait for other services
// to finalize based on context cancellation.
fmt.Println("\n\n")
log.Println("shutting down")
log.Println("Goddbye!....")
os.Exit(0)
}
I have been having problems of connections closed on load when tested with ab tool for 500 concurrent connections with 50000 requests on my mac that I solved by sending a header close connection in the GET request and now the test is successful on my mac.
However, when I tried to run the test in a windows 10 box I am again receiving messages like this:
2019/03/08 20:47:47 Error en response: Get http://localhost:9596/echo/javier: dial tcp [::1]:9596: bind: An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.
After googling for a while looking for a windows alternative to ulimit in order to change resource limits I have found messages like this:
I don't believe that current Windows O/S have a limit on the total
number of file descriptors, but the MS runtime library (msvcrt.dll)
has a per process limit of 2048, albeit as far as I know that's not
enforced by the O/S.
It can allegedly be increased only by building your own version of the
MS runtime library from source.
Then I am curious because I have the same kind of service made with Java and NodeJS and both can run the test successfuly in the same machines where my go app fails because the errors mentioned above.
So now my questions/doubts are:
what are Java and NodeJS doing different from go http server to be able to pass my test without reach OS limits?
What can I do to get my go services to be successful in any system as Java and NodeJS did?
Finally, is there any way to let my go services know the OS limits to prevent it to reach them and fail the tests?
This is issue is driving me crazy and even when it allowed me to learn a lot about http protocol is getting more dark everyday as I could not find a solution and I will love to have my app developed in go rather than in Java because it seems to be far better when runs well.
Thanks in advance
J

Proxy golang https

i am trying to make one get in https://www.google.com using proxy with authentication, i already passing header parameter
Proxy-Authorization
but proxy server return
Proxy Authentication Required
code:
package main
import (
"crypto/tls"
"encoding/base64"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://www.google.com.br", nil)
req.Header.Set("Host", "www.google.com.br")
proxyURL := url.URL{
Host: "IP-HERE:PORT-HEERE"}
transport := &http.Transport{
Proxy: http.ProxyURL(&proxyURL),
TLSClientConfig: &tls.Config{},
}
client := &http.Client{Transport: transport}
req.RequestURI = ""
auth := fmt.Sprintf("USER:PASSWORD")
basic := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
req.Header.Add("Proxy-Authorization", basic)
resp, err := client.Do(req)
if err != nil {
fmt.Printf("erro: %s", err)
}
fmt.Printf("code: %s", resp.StatusCode)
htmlData, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(os.Stdout, string(htmlData))
}
I have to pass another parameter?
When i perform one get in http://www.google.com.br, without https.. proxy authentication with success. why?
I found the solution. Golang don't pass header parameters in method CONNECT, then parameter Proxy-Authorization aren't sent to proxy server.
to resolve this, field ProxyConnectHeader was added to struct Transport. but this change until released, this change are only in master.
to test this new field using golang from master, i made on project in github and worked.
link to golang path
link to project in github that test this new field

Golang ReverseProxy with Apache2 SNI/Hostname error

i am writing my own ReverseProxy in Go.The ReverseProxy should connect my go-webserver and my apache2 webserver. But when I run my reverseproxy on another IP-Adress then my Apache2 webserver I got following error in my apache-logfile, when the reverseproxy sends the request to apache.
"Hosname xxxx provided via sni and hostname xxxx2 provided via http are different"
My Reverse Proxy and apache-webserver running on https.
Here some code:
func (p *Proxy) directorApache(req *http.Request) {
mainServer := fmt.Sprintf("%s:%d", Config.HostMain, Config.PortMain)
req.URL.Scheme = "https"
req.URL.Host = mainServer
}
func (p *Proxy) directorGo(req *http.Request) {
goServer := fmt.Sprintf("%s:%d", Config.GoHost, Config.GoPort)
req.URL.Scheme = "http"
req.URL.Host = goServer
}
func (p *Proxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
fmt.Println(req.URL.Path)
if p.isGoRequest(req) {
fmt.Println("GO")
p.goProxy.ServeHTTP(rw, req)
return
}
p.httpProxy.ServeHTTP(rw, req)
}
func main() {
var configPath = flag.String("conf", "./configReverse.json", "Path to the Json config file.")
flag.Parse()
proxy := New(*configPath)
cert, err := tls.LoadX509KeyPair(Config.PathCert, Config.PathPrivateKey)
if err != nil {
log.Fatalf("server: loadkeys: %s", err)
}
config := tls.Config{InsecureSkipVerify: true, Certificates: []tls.Certificate{cert}}
listener, err := net.Listen("tcp",
net.JoinHostPort(proxy.Host, strconv.Itoa(proxy.Port)))
if err != nil {
log.Fatalf("server: listen: %s", err)
}
log.Printf("server: listening on %s")
proxy.listener = tls.NewListener(listener, &config)
serverHTTPS := &http.Server{
Handler: proxy.mux,
TLSConfig: &config,
}
if err := serverHTTPS.Serve(proxy.listener); err != nil {
log.Fatal("SERVER ERROR:", err)
}
}
Perhaps someone has a idea about that issue.
Short example
Say you're starting an HTTP request to https://your-proxy.local. Your request handler takes the http.Request struct and rewrites its URL field to https://your-apache-backend.local.
What you have not considered, is that the original HTTP request also contained a Host header (Host: your-proxy.local). When passing that same request to http://your-apache-backend.local, the Host header in that request still says Host: your-proxy.local. And that's what Apache is complaining about.
Explanation
As you're using TLS with Server Name Indication (SNI), the request hostname will not only be used for DNS resolution, but also to select the SSL certificate that should be used to establish the TLS connection. The HTTP 1.1 Host header on the other hand is used to distinguish several virtual hosts by Apache. Both names must match. This issue is also mentioned in the Apache HTTPD wiki:
SNI/Request hostname mismatch, or SNI provides hostname and request doesn't.
This is a browser bug. Apache will reject the request with a 400-type error.
Solution
Also rewrite the Host header. If you want to preserve the original Host header, you can store it in an X-Forwarded-Host header (that's a non-standard header, but it's widely used in reverse proxies):
func (p *Proxy) directorApache(req *http.Request) {
mainServer := fmt.Sprintf("%s:%d", Config.HostMain, Config.PortMain)
req.URL.Scheme = "https"
req.URL.Host = mainServer
req.Header.Set("X-Forwarded-Host", req.Header().Get("Host"))
req.Host = mainServer
}

Mocking HTTPS responses in Go

I'm trying to write tests for a package that makes requests to a web service. I'm running into issues probably due to my lack of understanding of TLS.
Currently my test looks something like this:
func TestSimple() {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
fmt.Fprintf(w, `{ "fake" : "json data here" }`)
}))
transport := &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
return url.Parse(server.URL)
},
}
// Client is the type in my package that makes requests
client := Client{
c: http.Client{Transport: transport},
}
client.DoRequest() // ...
}
My package has a package variable (I'd like for it to be a constant..) for the base address of the web service to query. It is an https URL. The test server I created above is plain HTTP, no TLS.
By default, my test fails with the error "tls: first record does not look like a TLS handshake."
To get this to work, my tests change the package variable to a plain http URL instead of https before making the query.
Is there any way around this? Can I make the package variable a constant (https), and either set up a http.Transport that "downgrades" to unencrypted HTTP, or use httptest.NewTLSServer() instead?
(When I try to use NewTLSServer() I get "http: TLS handshake error from 127.0.0.1:45678: tls: oversized record received with length 20037")
Most of the behavior in net/http can be mocked, extended, or altered. Although http.Client is a concrete type that implements HTTP client semantics, all of its fields are exported and may be customized.
The Client.Transport field, in particular, may be replaced to make the Client do anything from using custom protocols (such as ftp:// or file://) to connecting directly to local handlers (without generating HTTP protocol bytes or sending anything over the network).
The client functions, such as http.Get, all utilize the exported http.DefaultClient package variable (which you may modify), so code that utilizes these convenience functions does not, for example, have to be changed to call methods on a custom Client variable. Note that while it would be unreasonable to modify global behavior in a publicly-available library, it's very useful to do so in applications and tests (including library tests).
http://play.golang.org/p/afljO086iB contains a custom http.RoundTripper that rewrites the request URL so that it'll be routed to a locally hosted httptest.Server, and another example that directly passes the request to an http.Handler, along with a custom http.ResponseWriter implementation, in order to create an http.Response. The second approach isn't as diligent as the first (it doesn't fill out as many fields in the Response value) but is more efficient, and should be compatible enough to work with most handlers and client callers.
The above-linked code is included below as well:
package main
import (
"fmt"
"io"
"log"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path"
"strings"
)
func Handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello %s\n", path.Base(r.URL.Path))
}
func main() {
s := httptest.NewServer(http.HandlerFunc(Handler))
u, err := url.Parse(s.URL)
if err != nil {
log.Fatalln("failed to parse httptest.Server URL:", err)
}
http.DefaultClient.Transport = RewriteTransport{URL: u}
resp, err := http.Get("https://google.com/path-one")
if err != nil {
log.Fatalln("failed to send first request:", err)
}
fmt.Println("[First Response]")
resp.Write(os.Stdout)
fmt.Print("\n", strings.Repeat("-", 80), "\n\n")
http.DefaultClient.Transport = HandlerTransport{http.HandlerFunc(Handler)}
resp, err = http.Get("https://google.com/path-two")
if err != nil {
log.Fatalln("failed to send second request:", err)
}
fmt.Println("[Second Response]")
resp.Write(os.Stdout)
}
// RewriteTransport is an http.RoundTripper that rewrites requests
// using the provided URL's Scheme and Host, and its Path as a prefix.
// The Opaque field is untouched.
// If Transport is nil, http.DefaultTransport is used
type RewriteTransport struct {
Transport http.RoundTripper
URL *url.URL
}
func (t RewriteTransport) RoundTrip(req *http.Request) (*http.Response, error) {
// note that url.URL.ResolveReference doesn't work here
// since t.u is an absolute url
req.URL.Scheme = t.URL.Scheme
req.URL.Host = t.URL.Host
req.URL.Path = path.Join(t.URL.Path, req.URL.Path)
rt := t.Transport
if rt == nil {
rt = http.DefaultTransport
}
return rt.RoundTrip(req)
}
type HandlerTransport struct{ h http.Handler }
func (t HandlerTransport) RoundTrip(req *http.Request) (*http.Response, error) {
r, w := io.Pipe()
resp := &http.Response{
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: make(http.Header),
Body: r,
Request: req,
}
ready := make(chan struct{})
prw := &pipeResponseWriter{r, w, resp, ready}
go func() {
defer w.Close()
t.h.ServeHTTP(prw, req)
}()
<-ready
return resp, nil
}
type pipeResponseWriter struct {
r *io.PipeReader
w *io.PipeWriter
resp *http.Response
ready chan<- struct{}
}
func (w *pipeResponseWriter) Header() http.Header {
return w.resp.Header
}
func (w *pipeResponseWriter) Write(p []byte) (int, error) {
if w.ready != nil {
w.WriteHeader(http.StatusOK)
}
return w.w.Write(p)
}
func (w *pipeResponseWriter) WriteHeader(status int) {
if w.ready == nil {
// already called
return
}
w.resp.StatusCode = status
w.resp.Status = fmt.Sprintf("%d %s", status, http.StatusText(status))
close(w.ready)
w.ready = nil
}
The reason you're getting the error http: TLS handshake error from 127.0.0.1:45678: tls: oversized record received with length 20037 is because https requires a domain name (not an IP Address). Domain names are SSL certificates are assigned to.
Start the httptest server in TLS mode with your own certs
cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
if err != nil {
log.Panic("bad server certs: ", err)
}
certs := []tls.Certificate{cert}
server = httptest.NewUnstartedServer(router)
server.TLS = &tls.Config{Certificates: certs}
server.StartTLS()
serverPort = ":" + strings.Split(server.URL, ":")[2] // it's always https://127.0.0.1:<port>
server.URL = "https://sub.domain.com" + serverPort
To provide a valid SSL certificate for a connection are the options of:
Not supplying a cert and key
Supplying a self-signed cert and key
Supplying a real valid cert and key
No Cert
If you don't supply your own cert, then an example.com cert is loaded as default.
Self-Signed Cert
To create a testing cert can use the included self-signed cert generator at $GOROOT/src/crypto/tls/generate_cert.go --host "*.domain.name"
You'll get x509: certificate signed by unknown authority warnings because it's self-signed so you'll need to have your client skip those warnings, by adding the following to your http.Transport field:
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}
Valid Real Cert
Finally, if you're going to use a real cert, then save the valid cert and key where they can be loaded.
The key here is to use server.URL = https://sub.domain.com to supply your own domain.
From Go 1.9+ you can use func (s *Server) Client() *http.Client in the httptest package:
Client returns an HTTP client configured for making requests to the server. It is configured to trust the server's TLS test certificate and will close its idle connections on Server.Close.
Example from the package:
package main
import (
"fmt"
"io"
"log"
"net/http"
"net/http/httptest"
)
func main() {
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, client")
}))
defer ts.Close()
client := ts.Client()
res, err := client.Get(ts.URL)
if err != nil {
log.Fatal(err)
}
greeting, err := io.ReadAll(res.Body)
res.Body.Close()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", greeting)
}

SCP Client in Go

I was struggling with and ssh client for golang but was told that the ciphers for the freesshd server was incompatible with the ssh client for Go, so I just installed another one (PowerShell Server) and I can successfully connect to the server.
My problem is not over because I now need to transfer files from local to remote, and this can only be done through scp. I was directed to this scp client for go and have two issues.
I run it and get this:
Where or how can I access the contents of id_rsa needed for privateKey? I just went in my .ssh folder and saw a github_rsa and used that private key, I'm sure that this is not the correct one to use but wouldn't I see some kind of error or invalid private key and not the result above?
The code you were directed to is broken. The example also uses the public key authentication, which is not necessarily your only option. If you can allow password authentication instead, you can make it a bit easier for yourself.
I just made an upload myself by modifying the example you used:
package main
import (
"code.google.com/p/go.crypto/ssh"
"fmt"
)
type password string
func (p password) Password(_ string) (string, error) {
return string(p), nil
}
func main() {
// Dial code is taken from the ssh package example
config := &ssh.ClientConfig{
User: "username",
Auth: []ssh.ClientAuth{
ssh.ClientAuthPassword(password("password")),
},
}
client, err := ssh.Dial("tcp", "127.0.0.1:22", config)
if err != nil {
panic("Failed to dial: " + err.Error())
}
session, err := client.NewSession()
if err != nil {
panic("Failed to create session: " + err.Error())
}
defer session.Close()
go func() {
w, _ := session.StdinPipe()
defer w.Close()
content := "123456789\n"
fmt.Fprintln(w, "C0644", len(content), "testfile")
fmt.Fprint(w, content)
fmt.Fprint(w, "\x00")
}()
if err := session.Run("/usr/bin/scp -qrt ./"); err != nil {
panic("Failed to run: " + err.Error())
}
}