Maison  >  Article  >  développement back-end  >  Connectez-vous à FTP via un proxy depuis Golang

Connectez-vous à FTP via un proxy depuis Golang

PHPz
PHPzavant
2024-02-09 12:00:09571parcourir

从 golang 通过代理连接到 ftp

L'éditeur PHP Zimo vous présente une méthode pour vous connecter au code Golang du serveur FTP en utilisant un proxy. Dans certains cas, nous devrons peut-être utiliser un serveur proxy lors de l'accès au serveur FTP afin d'augmenter la sécurité ou de résoudre les restrictions réseau. Golang est un langage de programmation puissant avec des bibliothèques réseau simples et faciles à utiliser, nous pouvons donc facilement implémenter cette fonctionnalité. Ensuite, nous utiliserons un exemple de code simple pour montrer comment utiliser Golang pour se connecter à un serveur FTP via un proxy.

Contenu de la question

Je dois me connecter au serveur FTP via un proxy et télécharger des fichiers à partir du code Golang. J'ai implémenté un client simple :

<code>package main

import (
    "bufio"
    "fmt"
    "github.com/jlaffaye/ftp"
    "io"
    "log"
    "net"
    "net/http"
    "os"
    "strings"
    "time"
)

var targetAddr = "ftp.dlptest.com"
var proxyAddr = "146.19.106.109:3128"
var user = "dlpuser"
var pass = "rNrKYTX9g7z3RgJRmxWuGHbeu"
var path = "/xxx.txt"

func connectViaProxy(network, address string) (net.Conn, error) {

    parts := strings.Split(address, ":")
    addr := fmt.Sprintf("%s:%s", targetAddr, parts[1])

    proxyConn, err := net.Dial(network, proxyAddr)
    if err != nil {
        return nil, err
    }

    req, err := http.NewRequest(http.MethodConnect, "http://"+addr, nil)
    if err != nil {
        proxyConn.Close()
        return nil, err
    }

    req.Header.Set("Accept", "*/*")
    req.Header.Set("User-Agent", "curl/8.1.2")
    req.Header.Set("Host", targetAddr+":21")

    err = req.Write(proxyConn)
    if err != nil {
        return nil, err
    }

    resp, err := http.ReadResponse(bufio.NewReader(proxyConn), req)
    if err != nil {
        proxyConn.Close()
        return nil, err
    }
    if resp.StatusCode != 200 {

        x, _ := io.ReadAll(resp.Body)
        fmt.Println(string(x))

        proxyConn.Close()
        return nil, fmt.Errorf("non-200 status code received from proxy: %v", resp.Status)
    }

    return proxyConn, nil
}

func main() {
    c, err := ftp.Dial(targetAddr+":21",
        ftp.DialWithTimeout(5*time.Second),
        ftp.DialWithDebugOutput(os.Stdin),
        ftp.DialWithDialFunc(connectViaProxy),
    )
    if err != nil {
        log.Fatal(err)
    }

    err = c.Login(user, pass)
    if err != nil {
        log.Fatal(err)
    }

    if r, err := c.Retr(path); err != nil {
        fmt.Println(err, ":<")
    } else {
        if reader, err := io.ReadAll(r); err != nil {
            fmt.Println(err, ":(")
        } else {
            fmt.Println(string(reader))
        }
    }

    if err = c.Quit(); err != nil {
        log.Fatal(err)
    }
}

</code>

Malheureusement, je reçois un 403 Forbidden lorsque j'essaie de me connecter. Normalement, je suppose qu'il s'agit d'une limitation du serveur, mais via curl, cela fonctionne parfaitement :

curl -vvv -x 146.19.106.109:3128 -u dlpuser:rNrKYTX9g7z3RgJRmxWuGHbeu ftp://ftp.dlptest.com/xxx.txt

Est-ce que quelqu'un sait pourquoi cela se produit ? Pour autant que je sache, curl utilise également http CONNECT sous le capot, donc je me demande ce qui me manque.

P.S. Ne vous inquiétez pas des informations d'identification dans le code - elles sont exposées pour les tests réseau

Solution de contournement

FTP sur le proxy HTTP n'est pas effectué via la requête CONNECT. Au lieu de cela, le proxy est invité à obtenir l'URL ftp://... à l'aide d'une requête GET normale. C’est aussi ce que fait curl. En Go, cela peut être fait comme ceci (gestion des erreurs omise pour plus de simplicité) :

// create the TCP connection to the proxy
conn, err := net.Dial("tcp", "146.19.106.109:3128")

// create the request with the ftp:// URL
req, err := http.NewRequest(http.MethodGet, "ftp://ftp.dlptest.com/xxx.txt", nil)
req.SetBasicAuth("dlpuser","rNrKYTX9g7z3RgJRmxWuGHbeu")

// don't use req.Write but req.WriteProxy, since the request line must
// contain the full URL and not only the path
err = req.WriteProxy(conn)

// read response
resp, err := http.ReadResponse(bufio.NewReader(conn), req)
body, _ := io.ReadAll(resp.Body)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer