Golangで作るFTPプロキシサーバ

 Golangで作るFTPプロキシサーバ

Go Conference 2018 Springで話した内容です。
話し手は、Golangを利用して、FTPプロキシサーバを開発しています。その際に起こった問題や、Golangにおける複数ソケットを扱う際のテクニックを紹介します。

1b838da2065660793d5b26f2cdc32de7?s=128

Kazuhiko Yamashita

April 15, 2018
Tweet

Transcript

  1. 7.
  2. 8.

    4,:

  3. 16.

    '51 'JMF5SBOTGFS1SPUPDPM wฏจςΩετͷίϚϯυૢ࡞ % ftp 127.0.0.1 2121 Connected to 127.0.0.1.

    220 Welcome on ftpserver Name (127.0.0.1:yamashitakazuhiko): test 331 OK Password: 230 Password ok, continue ftp> ls 227 Entering Passive Mode (127,0,0,1,224,164) 150 Using transfer connection drw-rw-rw- 1 ftp ftp 4096 Mar 28 06:38 virtual 226 Closing transfer connection
  4. 19.

    OFU-JTUFOͰίωΫγϣϯΛ͏͚Δ OFU-JTUFOFS HPSPVUJOF IBOEMFS HPSPVUJOF IBOEMFS HPSPVUJOF IBOEMFS DPOO DPOO

    DPOO listener, _ := net.Listen(“tcp”,”127.0.0.1:21") for { connection, _ := listener.Accept() ɹ // ίωΫγϣϯΛgroutine΁ }
  5. 20.

    ίωΫγϣϯ͝ͱʹίϚϯυΛಡΈࠐΈॲཧ reader = bufio.NewReader(connection) line, err := reader.ReadString('\n') => line:

    USER test ftp> open 127.0.0.1 2121 ftp> user test CVpP3FBEFSΛར༻͢Δ͜ͱͰ ιέοτ͔Βͷಡࠐ͕ศརʹ
  6. 21.

    ಉ࣌઀ଓ਺؅ཧ͢Δ OFU-JTUFOFS HPSPVUJOF IBOEMFS HPSPVUJOF IBOEMFS HPSPVUJOF IBOEMFS DPOO DPOO

    DPOO HPSPVUJOF։࢝࣌ʹΧ΢ϯτΞοϓ͠ɺ HPSPVUJOFͷऴྃ࣌ʹΧ΢ϯτμ΢ϯ͢Δ͜ͱͰ ಉ࣌઀ଓ਺Λ؅ཧ
  7. 22.

    *EMFλΠϜΞ΢τΛઃ͚Δ͜ͱͰࣗಈ੾அ OFU-JTUFOFS HPSPVUJOF IBOEMFS HPSPVUJOF IBOEMFS HPSPVUJOF IBOEMFS DPOO DPOO

    DPOO OFU$POO4FU%FBEMJOFΛར༻͠ɺૢ࡞ͷͳ͍ΫϥΠΞϯτΛ λΠϜΞ΢τॲཧ
  8. 23.

    OFU$POO4FU%FBEMJOF for { connection.SetDeadline( ɹɹɹtime.Now().Add( ɹɹɹtime.Duration(time.Second.Nanoseconds() * int64(idleTimeout))) ɹ )

    // 1ߦͣͭಡΉ line, err := reader.ReadString('\n') // ड͚औͬͨίϚϯυͷॲཧ } %FBEMJOF౸ୡͨ͠৔߹ɺJPUJNFPVU
  9. 24.

    '51ϓϩΩγ OFU-JTUFOFS HPSPVUJOF IBOEMFS HPSPVUJOF IBOEMFS HPSPVUJOF IBOEMFS DPOO DPOO

    DPOO PSJHJO PSJHJO PSJHJO $0.."/% $0.."/% $0.."/% $0.."/% $0.."/% $0.."/% HPSPVUJOF୯ҐͰϓϩΩγίωΫγϣϯΛுΔ
  10. 27.
  11. 30.

    1"47ίϚϯυ͸த਎Λॻ͖׵͑Δ &OUFSJOH1BTTJWF.PEF        º

      QGUQ PSJHJO DMJFOU 1"47 1"47  
  12. 38.

    σʔλίωΫγϣϯͷϓϩΩγ QGUQ PSJHJO DMJFOU σʔλίωΫγϣϯཁٻ DMJFOU͔Βݟͨ৔߹ɺQGUQ͸αʔόɺ ΦϦδϯ͔Βݟͨ৔߹ɺQGUQ͸ΫϥΠΞϯτͷڍಈ͕ٻΊΒΕΔ EBUBDPOFDUJPO EBUBDPOFDUJPO σʔλίωΫγϣϯཁٻ

    999Ͱ-JTUFO։࢝ :::Ͱ-JTUFO։࢝ :::UPDMJFOU΁σʔλసૹ։࢝ 999UPQGUQ΁σʔλసૹ։࢝ ϑΝΠϧసૹཁٻ ϑΝΠϧసૹཁٻ
  13. 39.

    ɹɹEPXOMPBEHPSPVUJOF func proxy() { … // ϦϨʔ༻ͷgoroutineΛىಈ eg.Go(func() error {

    return relay(ctx, server, client) }) eg.Go(func() error { return relay(ctx, client, server) }) // ׬ྃ·Ͱ଴ͪ߹ΘͤΔ if err := eg.Wait(); err != nil { return err } } HSPVUJOFͰϓϩΩγ PSJHJO DMJFOU ɹɹVQMPBEHPSPVUJOF QGUQ
  14. 40.

    ී௨ʹ΍Δͱ͏·͍͔͘ͳ͍ func relay(from, to net.Conn) error { buff := make([]byte,

    BUFFER_SIZE) for { select { case <-ctx.Done(): return ctx.Err() default: if err := from.Read(buff); err != nil { return errr } if err := to.Write(b); err != nil { return errr } } } } Ξοϓϩʔυɺ΋͘͠͸μ΢ϯϩʔυͷऴྃͰ ྆ํίωΫγϣϯΛऴ͍ྃͨ͠ DUY%POF  Ͱ΋ऴྃ͠ͳ͍
  15. 42.

    3FBE͸ϒϩοΩϯά func relay(from, to net.Conn) error { buff := make([]byte,

    BUFFER_SIZE) for { select { case <-ctx.Done(): return ctx.Err() default: if err := from.Read(buff); err != nil { return errr } if err := to.Write(b); err != nil { return errr } } } } 3FBEͰϒϩοΩϯά͞ΕΔ͕Ώ͑ʹɺ ࣍ͷϧʔϓ΁͍͔ͳ͍
  16. 43.

    ϊϯϒϩοΩϯά3FBE for { select { case <-ctx.Done(): return ctx.Err() case

    err := <-errChan: return err // ಡࠐgoroutineΛىಈ͠ɺඇಉظͰಡΈࠐΉ case b := <-read: _, err := to.Write(b) if err != nil { return err } } } νϟϯωϧܦ༝ͰಡΈࠐΉ͜ͱʹΑΓ ϊϯϒϩοΩϯά΁
  17. 44.

    -FBLDPOUFYU8JUI$BODFM NBJO HPSPVUJOF HPSPVUJOF SFUVSO DUY%POF ctx, done := context.WithCancel(context.Background())

    defer done() eg, ctx := errgroup.WithContext(ctx) // ϦϨʔ༻ͷgoroutineΛىಈ eg.Go(func() error { return p.relay(ctx, server, client) }) eg.Go(func() error { return p.relay(ctx, client, server }) // ׬ྃ·Ͱ଴ͪ߹ΘͤΔ if err := eg.Wait(); err != nil { return err } EPOF
  18. 45.

    -FBLDPOOFDUJPO$MPTF  HPGVOD \   GPS\   

    O FSSGSPN3FBE CV⒎     JGFSSOJM\     FSS$IBOFSS     SFUVSO    ^    SFBECV⒎<O>   ^  ^  ίωΫγϣϯΤϥʔ͕ൃੜɺ ϒϩοΫ͕ղআ͞ΕΔ for { select { case <-ctx.Done(): from.Close() case err := <-errChan: return err case b := <-read: _, err := to.Write(b) if err != nil { return err } } } ૬ํͷసૹ͕ऴΘΓ࣍ୈ ίωΫγϣϯΛ Ϋϩʔζ Τϥʔνϟϯωϧܦ༝ Ͱॲཧऴྃ
  19. 48.