Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

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

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

Kazuhiko Yamashita

April 15, 2018
Tweet

More Decks by Kazuhiko Yamashita

Other Decks in Programming

Transcript

  1. 4,:

  2. '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
  3. 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΁ }
  4. ίωΫγϣϯ͝ͱʹίϚϯυΛಡΈࠐΈॲཧ reader = bufio.NewReader(connection) line, err := reader.ReadString('\n') => line:

    USER test ftp> open 127.0.0.1 2121 ftp> user test CVpP3FBEFSΛར༻͢Δ͜ͱͰ ιέοτ͔Βͷಡࠐ͕ศརʹ
  5. ಉ࣌઀ଓ਺؅ཧ͢Δ OFU-JTUFOFS HPSPVUJOF IBOEMFS HPSPVUJOF IBOEMFS HPSPVUJOF IBOEMFS DPOO DPOO

    DPOO HPSPVUJOF։࢝࣌ʹΧ΢ϯτΞοϓ͠ɺ HPSPVUJOFͷऴྃ࣌ʹΧ΢ϯτμ΢ϯ͢Δ͜ͱͰ ಉ࣌઀ଓ਺Λ؅ཧ
  6. *EMFλΠϜΞ΢τΛઃ͚Δ͜ͱͰࣗಈ੾அ OFU-JTUFOFS HPSPVUJOF IBOEMFS HPSPVUJOF IBOEMFS HPSPVUJOF IBOEMFS DPOO DPOO

    DPOO OFU$POO4FU%FBEMJOFΛར༻͠ɺૢ࡞ͷͳ͍ΫϥΠΞϯτΛ λΠϜΞ΢τॲཧ
  7. OFU$POO4FU%FBEMJOF for { connection.SetDeadline( ɹɹɹtime.Now().Add( ɹɹɹtime.Duration(time.Second.Nanoseconds() * int64(idleTimeout))) ɹ )

    // 1ߦͣͭಡΉ line, err := reader.ReadString('\n') // ड͚औͬͨίϚϯυͷॲཧ } %FBEMJOF౸ୡͨ͠৔߹ɺJPUJNFPVU
  8. '51ϓϩΩγ OFU-JTUFOFS HPSPVUJOF IBOEMFS HPSPVUJOF IBOEMFS HPSPVUJOF IBOEMFS DPOO DPOO

    DPOO PSJHJO PSJHJO PSJHJO $0.."/% $0.."/% $0.."/% $0.."/% $0.."/% $0.."/% HPSPVUJOF୯ҐͰϓϩΩγίωΫγϣϯΛுΔ
  9. 1"47ίϚϯυ͸த਎Λॻ͖׵͑Δ &OUFSJOH1BTTJWF.PEF        º

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

    999Ͱ-JTUFO։࢝ :::Ͱ-JTUFO։࢝ :::UPDMJFOU΁σʔλసૹ։࢝ 999UPQGUQ΁σʔλసૹ։࢝ ϑΝΠϧసૹཁٻ ϑΝΠϧసૹཁٻ
  11. ɹɹ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
  12. ී௨ʹ΍Δͱ͏·͍͔͘ͳ͍ 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  Ͱ΋ऴྃ͠ͳ͍
  13. 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ͰϒϩοΩϯά͞ΕΔ͕Ώ͑ʹɺ ࣍ͷϧʔϓ΁͍͔ͳ͍
  14. ϊϯϒϩοΩϯά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 } } } νϟϯωϧܦ༝ͰಡΈࠐΉ͜ͱʹΑΓ ϊϯϒϩοΩϯά΁
  15. -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
  16. -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 } } } ૬ํͷసૹ͕ऴΘΓ࣍ୈ ίωΫγϣϯΛ Ϋϩʔζ Τϥʔνϟϯωϧܦ༝ Ͱॲཧऴྃ