go.etcd.io/etcd@v3.3.27+incompatible/pkg/proxy/server.go (about) 1 // Copyright 2018 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package proxy 16 17 import ( 18 "fmt" 19 "io" 20 mrand "math/rand" 21 "net" 22 "net/http" 23 "net/url" 24 "strings" 25 "sync" 26 "time" 27 28 "github.com/coreos/etcd/pkg/transport" 29 30 humanize "github.com/dustin/go-humanize" 31 "go.uber.org/zap" 32 ) 33 34 // Server defines proxy server layer that simulates common network faults, 35 // such as latency spikes, packet drop/corruption, etc.. 36 type Server interface { 37 // From returns proxy source address in "scheme://host:port" format. 38 From() string 39 // To returns proxy destination address in "scheme://host:port" format. 40 To() string 41 42 // Ready returns when proxy is ready to serve. 43 Ready() <-chan struct{} 44 // Done returns when proxy has been closed. 45 Done() <-chan struct{} 46 // Error sends errors while serving proxy. 47 Error() <-chan error 48 // Close closes listener and transport. 49 Close() error 50 51 // DelayAccept adds latency ± random variable to accepting new incoming connections. 52 DelayAccept(latency, rv time.Duration) 53 // UndelayAccept removes sending latencies. 54 UndelayAccept() 55 // LatencyAccept returns current latency on accepting new incoming connections. 56 LatencyAccept() time.Duration 57 // DelayTx adds latency ± random variable to "sending" layer. 58 DelayTx(latency, rv time.Duration) 59 // UndelayTx removes sending latencies. 60 UndelayTx() 61 // LatencyTx returns current send latency. 62 LatencyTx() time.Duration 63 // DelayRx adds latency ± random variable to "receiving" layer. 64 DelayRx(latency, rv time.Duration) 65 // UndelayRx removes "receiving" latencies. 66 UndelayRx() 67 // LatencyRx returns current receive latency. 68 LatencyRx() time.Duration 69 70 // PauseAccept stops accepting new connections. 71 PauseAccept() 72 // UnpauseAccept removes pause operation on accepting new connections. 73 UnpauseAccept() 74 // PauseTx stops "forwarding" packets. 75 PauseTx() 76 // UnpauseTx removes "forwarding" pause operation. 77 UnpauseTx() 78 // PauseRx stops "receiving" packets to client. 79 PauseRx() 80 // UnpauseRx removes "receiving" pause operation. 81 UnpauseRx() 82 83 // BlackholeTx drops all incoming packets before "forwarding". 84 BlackholeTx() 85 // UnblackholeTx removes blackhole operation on "sending". 86 UnblackholeTx() 87 // BlackholeRx drops all incoming packets to client. 88 BlackholeRx() 89 // UnblackholeRx removes blackhole operation on "receiving". 90 UnblackholeRx() 91 92 // CorruptTx corrupts incoming packets from the listener. 93 CorruptTx(f func(data []byte) []byte) 94 // UncorruptTx removes corrupt operation on "forwarding". 95 UncorruptTx() 96 // CorruptRx corrupts incoming packets to client. 97 CorruptRx(f func(data []byte) []byte) 98 // UncorruptRx removes corrupt operation on "receiving". 99 UncorruptRx() 100 101 // ResetListener closes and restarts listener. 102 ResetListener() error 103 } 104 105 type proxyServer struct { 106 lg *zap.Logger 107 108 from, to url.URL 109 tlsInfo transport.TLSInfo 110 dialTimeout time.Duration 111 bufferSize int 112 retryInterval time.Duration 113 114 readyc chan struct{} 115 donec chan struct{} 116 errc chan error 117 118 closeOnce sync.Once 119 closeWg sync.WaitGroup 120 121 listenerMu sync.RWMutex 122 listener net.Listener 123 124 latencyAcceptMu sync.RWMutex 125 latencyAccept time.Duration 126 latencyTxMu sync.RWMutex 127 latencyTx time.Duration 128 latencyRxMu sync.RWMutex 129 latencyRx time.Duration 130 131 corruptTxMu sync.RWMutex 132 corruptTx func(data []byte) []byte 133 corruptRxMu sync.RWMutex 134 corruptRx func(data []byte) []byte 135 136 acceptMu sync.Mutex 137 pauseAcceptc chan struct{} 138 txMu sync.Mutex 139 pauseTxc chan struct{} 140 blackholeTxc chan struct{} 141 rxMu sync.Mutex 142 pauseRxc chan struct{} 143 blackholeRxc chan struct{} 144 } 145 146 // ServerConfig defines proxy server configuration. 147 type ServerConfig struct { 148 Logger *zap.Logger 149 From url.URL 150 To url.URL 151 TLSInfo transport.TLSInfo 152 DialTimeout time.Duration 153 BufferSize int 154 RetryInterval time.Duration 155 } 156 157 var ( 158 defaultDialTimeout = 3 * time.Second 159 defaultBufferSize = 48 * 1024 160 defaultRetryInterval = 10 * time.Millisecond 161 defaultLogger *zap.Logger 162 ) 163 164 func init() { 165 var err error 166 defaultLogger, err = zap.NewProduction() 167 if err != nil { 168 panic(err) 169 } 170 } 171 172 // NewServer returns a proxy implementation with no iptables/tc dependencies. 173 // The proxy layer overhead is <1ms. 174 func NewServer(cfg ServerConfig) Server { 175 p := &proxyServer{ 176 lg: cfg.Logger, 177 178 from: cfg.From, 179 to: cfg.To, 180 tlsInfo: cfg.TLSInfo, 181 dialTimeout: cfg.DialTimeout, 182 bufferSize: cfg.BufferSize, 183 retryInterval: cfg.RetryInterval, 184 185 readyc: make(chan struct{}), 186 donec: make(chan struct{}), 187 errc: make(chan error, 16), 188 189 pauseAcceptc: make(chan struct{}), 190 pauseTxc: make(chan struct{}), 191 blackholeTxc: make(chan struct{}), 192 pauseRxc: make(chan struct{}), 193 blackholeRxc: make(chan struct{}), 194 } 195 if p.dialTimeout == 0 { 196 p.dialTimeout = defaultDialTimeout 197 } 198 if p.bufferSize == 0 { 199 p.bufferSize = defaultBufferSize 200 } 201 if p.retryInterval == 0 { 202 p.retryInterval = defaultRetryInterval 203 } 204 if p.lg == nil { 205 p.lg = defaultLogger 206 } 207 close(p.pauseAcceptc) 208 close(p.pauseTxc) 209 close(p.pauseRxc) 210 211 if strings.HasPrefix(p.from.Scheme, "http") { 212 p.from.Scheme = "tcp" 213 } 214 if strings.HasPrefix(p.to.Scheme, "http") { 215 p.to.Scheme = "tcp" 216 } 217 218 var ln net.Listener 219 var err error 220 if !p.tlsInfo.Empty() { 221 ln, err = transport.NewListener(p.from.Host, p.from.Scheme, &p.tlsInfo) 222 } else { 223 ln, err = net.Listen(p.from.Scheme, p.from.Host) 224 } 225 if err != nil { 226 p.errc <- err 227 p.Close() 228 return p 229 } 230 p.listener = ln 231 232 p.closeWg.Add(1) 233 go p.listenAndServe() 234 235 p.lg.Info("started proxying", zap.String("from", p.From()), zap.String("to", p.To())) 236 return p 237 } 238 239 func (p *proxyServer) From() string { 240 return fmt.Sprintf("%s://%s", p.from.Scheme, p.from.Host) 241 } 242 243 func (p *proxyServer) To() string { 244 return fmt.Sprintf("%s://%s", p.to.Scheme, p.to.Host) 245 } 246 247 // TODO: implement packet reordering from multiple TCP connections 248 // buffer packets per connection for awhile, reorder before transmit 249 // - https://github.com/coreos/etcd/issues/5614 250 // - https://github.com/coreos/etcd/pull/6918#issuecomment-264093034 251 252 func (p *proxyServer) listenAndServe() { 253 defer p.closeWg.Done() 254 255 p.lg.Info("proxy is listening on", zap.String("from", p.From())) 256 close(p.readyc) 257 258 for { 259 p.acceptMu.Lock() 260 pausec := p.pauseAcceptc 261 p.acceptMu.Unlock() 262 select { 263 case <-pausec: 264 case <-p.donec: 265 return 266 } 267 268 p.latencyAcceptMu.RLock() 269 lat := p.latencyAccept 270 p.latencyAcceptMu.RUnlock() 271 if lat > 0 { 272 select { 273 case <-time.After(lat): 274 case <-p.donec: 275 return 276 } 277 } 278 279 p.listenerMu.RLock() 280 ln := p.listener 281 p.listenerMu.RUnlock() 282 283 in, err := ln.Accept() 284 if err != nil { 285 select { 286 case p.errc <- err: 287 select { 288 case <-p.donec: 289 return 290 default: 291 } 292 case <-p.donec: 293 return 294 } 295 p.lg.Debug("listener accept error", zap.Error(err)) 296 297 if strings.HasSuffix(err.Error(), "use of closed network connection") { 298 select { 299 case <-time.After(p.retryInterval): 300 case <-p.donec: 301 return 302 } 303 p.lg.Debug("listener is closed; retry listening on", zap.String("from", p.From())) 304 305 if err = p.ResetListener(); err != nil { 306 select { 307 case p.errc <- err: 308 select { 309 case <-p.donec: 310 return 311 default: 312 } 313 case <-p.donec: 314 return 315 } 316 p.lg.Warn("failed to reset listener", zap.Error(err)) 317 } 318 } 319 320 continue 321 } 322 323 var out net.Conn 324 if !p.tlsInfo.Empty() { 325 var tp *http.Transport 326 tp, err = transport.NewTransport(p.tlsInfo, p.dialTimeout) 327 if err != nil { 328 select { 329 case p.errc <- err: 330 select { 331 case <-p.donec: 332 return 333 default: 334 } 335 case <-p.donec: 336 return 337 } 338 continue 339 } 340 out, err = tp.Dial(p.to.Scheme, p.to.Host) 341 } else { 342 out, err = net.Dial(p.to.Scheme, p.to.Host) 343 } 344 if err != nil { 345 select { 346 case p.errc <- err: 347 select { 348 case <-p.donec: 349 return 350 default: 351 } 352 case <-p.donec: 353 return 354 } 355 p.lg.Debug("failed to dial", zap.Error(err)) 356 continue 357 } 358 359 go func() { 360 // read incoming bytes from listener, dispatch to outgoing connection 361 p.transmit(out, in) 362 out.Close() 363 in.Close() 364 }() 365 go func() { 366 // read response from outgoing connection, write back to listener 367 p.receive(in, out) 368 in.Close() 369 out.Close() 370 }() 371 } 372 } 373 374 func (p *proxyServer) transmit(dst io.Writer, src io.Reader) { p.ioCopy(dst, src, true) } 375 func (p *proxyServer) receive(dst io.Writer, src io.Reader) { p.ioCopy(dst, src, false) } 376 func (p *proxyServer) ioCopy(dst io.Writer, src io.Reader, proxySend bool) { 377 buf := make([]byte, p.bufferSize) 378 for { 379 nr, err := src.Read(buf) 380 if err != nil { 381 if err == io.EOF { 382 return 383 } 384 // connection already closed 385 if strings.HasSuffix(err.Error(), "read: connection reset by peer") { 386 return 387 } 388 if strings.HasSuffix(err.Error(), "use of closed network connection") { 389 return 390 } 391 select { 392 case p.errc <- err: 393 select { 394 case <-p.donec: 395 return 396 default: 397 } 398 case <-p.donec: 399 return 400 } 401 p.lg.Debug("failed to read", zap.Error(err)) 402 return 403 } 404 if nr == 0 { 405 return 406 } 407 data := buf[:nr] 408 409 var pausec chan struct{} 410 var blackholec chan struct{} 411 if proxySend { 412 p.txMu.Lock() 413 pausec = p.pauseTxc 414 blackholec = p.blackholeTxc 415 p.txMu.Unlock() 416 } else { 417 p.rxMu.Lock() 418 pausec = p.pauseRxc 419 blackholec = p.blackholeRxc 420 p.rxMu.Unlock() 421 } 422 select { 423 case <-pausec: 424 case <-p.donec: 425 return 426 } 427 blackholed := false 428 select { 429 case <-blackholec: 430 blackholed = true 431 case <-p.donec: 432 return 433 default: 434 } 435 if blackholed { 436 if proxySend { 437 p.lg.Debug( 438 "dropped", 439 zap.String("data-size", humanize.Bytes(uint64(nr))), 440 zap.String("from", p.From()), 441 zap.String("to", p.To()), 442 ) 443 } else { 444 p.lg.Debug( 445 "dropped", 446 zap.String("data-size", humanize.Bytes(uint64(nr))), 447 zap.String("from", p.To()), 448 zap.String("to", p.From()), 449 ) 450 } 451 continue 452 } 453 454 var lat time.Duration 455 if proxySend { 456 p.latencyTxMu.RLock() 457 lat = p.latencyTx 458 p.latencyTxMu.RUnlock() 459 } else { 460 p.latencyRxMu.RLock() 461 lat = p.latencyRx 462 p.latencyRxMu.RUnlock() 463 } 464 if lat > 0 { 465 select { 466 case <-time.After(lat): 467 case <-p.donec: 468 return 469 } 470 } 471 472 if proxySend { 473 p.corruptTxMu.RLock() 474 if p.corruptTx != nil { 475 data = p.corruptTx(data) 476 } 477 p.corruptTxMu.RUnlock() 478 } else { 479 p.corruptRxMu.RLock() 480 if p.corruptRx != nil { 481 data = p.corruptRx(data) 482 } 483 p.corruptRxMu.RUnlock() 484 } 485 486 var nw int 487 nw, err = dst.Write(data) 488 if err != nil { 489 if err == io.EOF { 490 return 491 } 492 select { 493 case p.errc <- err: 494 select { 495 case <-p.donec: 496 return 497 default: 498 } 499 case <-p.donec: 500 return 501 } 502 if proxySend { 503 p.lg.Debug("failed to write while sending", zap.Error(err)) 504 } else { 505 p.lg.Debug("failed to write while receiving", zap.Error(err)) 506 } 507 return 508 } 509 510 if nr != nw { 511 select { 512 case p.errc <- io.ErrShortWrite: 513 select { 514 case <-p.donec: 515 return 516 default: 517 } 518 case <-p.donec: 519 return 520 } 521 if proxySend { 522 p.lg.Debug( 523 "failed to write while sending; read/write bytes are different", 524 zap.Int("read-bytes", nr), 525 zap.Int("write-bytes", nw), 526 zap.Error(io.ErrShortWrite), 527 ) 528 } else { 529 p.lg.Debug( 530 "failed to write while receiving; read/write bytes are different", 531 zap.Int("read-bytes", nr), 532 zap.Int("write-bytes", nw), 533 zap.Error(io.ErrShortWrite), 534 ) 535 } 536 return 537 } 538 539 if proxySend { 540 p.lg.Debug( 541 "transmitted", 542 zap.String("data-size", humanize.Bytes(uint64(nr))), 543 zap.String("from", p.From()), 544 zap.String("to", p.To()), 545 ) 546 } else { 547 p.lg.Debug( 548 "received", 549 zap.String("data-size", humanize.Bytes(uint64(nr))), 550 zap.String("from", p.To()), 551 zap.String("to", p.From()), 552 ) 553 } 554 555 } 556 } 557 558 func (p *proxyServer) Ready() <-chan struct{} { return p.readyc } 559 func (p *proxyServer) Done() <-chan struct{} { return p.donec } 560 func (p *proxyServer) Error() <-chan error { return p.errc } 561 func (p *proxyServer) Close() (err error) { 562 p.closeOnce.Do(func() { 563 close(p.donec) 564 p.listenerMu.Lock() 565 if p.listener != nil { 566 err = p.listener.Close() 567 p.lg.Info( 568 "closed proxy listener", 569 zap.String("from", p.From()), 570 zap.String("to", p.To()), 571 ) 572 } 573 p.lg.Sync() 574 p.listenerMu.Unlock() 575 }) 576 p.closeWg.Wait() 577 return err 578 } 579 580 func (p *proxyServer) DelayAccept(latency, rv time.Duration) { 581 if latency <= 0 { 582 return 583 } 584 d := computeLatency(latency, rv) 585 p.latencyAcceptMu.Lock() 586 p.latencyAccept = d 587 p.latencyAcceptMu.Unlock() 588 589 p.lg.Info( 590 "set accept latency", 591 zap.Duration("latency", d), 592 zap.Duration("given-latency", latency), 593 zap.Duration("given-latency-random-variable", rv), 594 zap.String("from", p.From()), 595 zap.String("to", p.To()), 596 ) 597 } 598 599 func (p *proxyServer) UndelayAccept() { 600 p.latencyAcceptMu.Lock() 601 d := p.latencyAccept 602 p.latencyAccept = 0 603 p.latencyAcceptMu.Unlock() 604 605 p.lg.Info( 606 "removed accept latency", 607 zap.Duration("latency", d), 608 zap.String("from", p.From()), 609 zap.String("to", p.To()), 610 ) 611 } 612 613 func (p *proxyServer) LatencyAccept() time.Duration { 614 p.latencyAcceptMu.RLock() 615 d := p.latencyAccept 616 p.latencyAcceptMu.RUnlock() 617 return d 618 } 619 620 func (p *proxyServer) DelayTx(latency, rv time.Duration) { 621 if latency <= 0 { 622 return 623 } 624 d := computeLatency(latency, rv) 625 p.latencyTxMu.Lock() 626 p.latencyTx = d 627 p.latencyTxMu.Unlock() 628 629 p.lg.Info( 630 "set transmit latency", 631 zap.Duration("latency", d), 632 zap.Duration("given-latency", latency), 633 zap.Duration("given-latency-random-variable", rv), 634 zap.String("from", p.From()), 635 zap.String("to", p.To()), 636 ) 637 } 638 639 func (p *proxyServer) UndelayTx() { 640 p.latencyTxMu.Lock() 641 d := p.latencyTx 642 p.latencyTx = 0 643 p.latencyTxMu.Unlock() 644 645 p.lg.Info( 646 "removed transmit latency", 647 zap.Duration("latency", d), 648 zap.String("from", p.From()), 649 zap.String("to", p.To()), 650 ) 651 } 652 653 func (p *proxyServer) LatencyTx() time.Duration { 654 p.latencyTxMu.RLock() 655 d := p.latencyTx 656 p.latencyTxMu.RUnlock() 657 return d 658 } 659 660 func (p *proxyServer) DelayRx(latency, rv time.Duration) { 661 if latency <= 0 { 662 return 663 } 664 d := computeLatency(latency, rv) 665 p.latencyRxMu.Lock() 666 p.latencyRx = d 667 p.latencyRxMu.Unlock() 668 669 p.lg.Info( 670 "set receive latency", 671 zap.Duration("latency", d), 672 zap.Duration("given-latency", latency), 673 zap.Duration("given-latency-random-variable", rv), 674 zap.String("from", p.To()), 675 zap.String("to", p.From()), 676 ) 677 } 678 679 func (p *proxyServer) UndelayRx() { 680 p.latencyRxMu.Lock() 681 d := p.latencyRx 682 p.latencyRx = 0 683 p.latencyRxMu.Unlock() 684 685 p.lg.Info( 686 "removed receive latency", 687 zap.Duration("latency", d), 688 zap.String("from", p.To()), 689 zap.String("to", p.From()), 690 ) 691 } 692 693 func (p *proxyServer) LatencyRx() time.Duration { 694 p.latencyRxMu.RLock() 695 d := p.latencyRx 696 p.latencyRxMu.RUnlock() 697 return d 698 } 699 700 func computeLatency(lat, rv time.Duration) time.Duration { 701 if rv == 0 { 702 return lat 703 } 704 if rv < 0 { 705 rv *= -1 706 } 707 if rv > lat { 708 rv = lat / 10 709 } 710 now := time.Now() 711 mrand.Seed(int64(now.Nanosecond())) 712 sign := 1 713 if now.Second()%2 == 0 { 714 sign = -1 715 } 716 return lat + time.Duration(int64(sign)*mrand.Int63n(rv.Nanoseconds())) 717 } 718 719 func (p *proxyServer) PauseAccept() { 720 p.acceptMu.Lock() 721 p.pauseAcceptc = make(chan struct{}) 722 p.acceptMu.Unlock() 723 724 p.lg.Info( 725 "paused accepting new connections", 726 zap.String("from", p.From()), 727 zap.String("to", p.To()), 728 ) 729 } 730 731 func (p *proxyServer) UnpauseAccept() { 732 p.acceptMu.Lock() 733 select { 734 case <-p.pauseAcceptc: // already unpaused 735 case <-p.donec: 736 p.acceptMu.Unlock() 737 return 738 default: 739 close(p.pauseAcceptc) 740 } 741 p.acceptMu.Unlock() 742 743 p.lg.Info( 744 "unpaused accepting new connections", 745 zap.String("from", p.From()), 746 zap.String("to", p.To()), 747 ) 748 } 749 750 func (p *proxyServer) PauseTx() { 751 p.txMu.Lock() 752 p.pauseTxc = make(chan struct{}) 753 p.txMu.Unlock() 754 755 p.lg.Info( 756 "paused transmit listen", 757 zap.String("from", p.From()), 758 zap.String("to", p.To()), 759 ) 760 } 761 762 func (p *proxyServer) UnpauseTx() { 763 p.txMu.Lock() 764 select { 765 case <-p.pauseTxc: // already unpaused 766 case <-p.donec: 767 p.txMu.Unlock() 768 return 769 default: 770 close(p.pauseTxc) 771 } 772 p.txMu.Unlock() 773 774 p.lg.Info( 775 "unpaused transmit listen", 776 zap.String("from", p.From()), 777 zap.String("to", p.To()), 778 ) 779 } 780 781 func (p *proxyServer) PauseRx() { 782 p.rxMu.Lock() 783 p.pauseRxc = make(chan struct{}) 784 p.rxMu.Unlock() 785 786 p.lg.Info( 787 "paused receive listen", 788 zap.String("from", p.To()), 789 zap.String("to", p.From()), 790 ) 791 } 792 793 func (p *proxyServer) UnpauseRx() { 794 p.rxMu.Lock() 795 select { 796 case <-p.pauseRxc: // already unpaused 797 case <-p.donec: 798 p.rxMu.Unlock() 799 return 800 default: 801 close(p.pauseRxc) 802 } 803 p.rxMu.Unlock() 804 805 p.lg.Info( 806 "unpaused receive listen", 807 zap.String("from", p.To()), 808 zap.String("to", p.From()), 809 ) 810 } 811 812 func (p *proxyServer) BlackholeTx() { 813 p.txMu.Lock() 814 select { 815 case <-p.blackholeTxc: // already blackholed 816 case <-p.donec: 817 p.txMu.Unlock() 818 return 819 default: 820 close(p.blackholeTxc) 821 } 822 p.txMu.Unlock() 823 824 p.lg.Info( 825 "blackholed transmit", 826 zap.String("from", p.From()), 827 zap.String("to", p.To()), 828 ) 829 } 830 831 func (p *proxyServer) UnblackholeTx() { 832 p.txMu.Lock() 833 p.blackholeTxc = make(chan struct{}) 834 p.txMu.Unlock() 835 836 p.lg.Info( 837 "unblackholed transmit", 838 zap.String("from", p.From()), 839 zap.String("to", p.To()), 840 ) 841 } 842 843 func (p *proxyServer) BlackholeRx() { 844 p.rxMu.Lock() 845 select { 846 case <-p.blackholeRxc: // already blackholed 847 case <-p.donec: 848 p.rxMu.Unlock() 849 return 850 default: 851 close(p.blackholeRxc) 852 } 853 p.rxMu.Unlock() 854 855 p.lg.Info( 856 "blackholed receive", 857 zap.String("from", p.To()), 858 zap.String("to", p.From()), 859 ) 860 } 861 862 func (p *proxyServer) UnblackholeRx() { 863 p.rxMu.Lock() 864 p.blackholeRxc = make(chan struct{}) 865 p.rxMu.Unlock() 866 867 p.lg.Info( 868 "unblackholed receive", 869 zap.String("from", p.To()), 870 zap.String("to", p.From()), 871 ) 872 } 873 874 func (p *proxyServer) CorruptTx(f func([]byte) []byte) { 875 p.corruptTxMu.Lock() 876 p.corruptTx = f 877 p.corruptTxMu.Unlock() 878 879 p.lg.Info( 880 "corrupting transmit", 881 zap.String("from", p.From()), 882 zap.String("to", p.To()), 883 ) 884 } 885 886 func (p *proxyServer) UncorruptTx() { 887 p.corruptTxMu.Lock() 888 p.corruptTx = nil 889 p.corruptTxMu.Unlock() 890 891 p.lg.Info( 892 "stopped corrupting transmit", 893 zap.String("from", p.From()), 894 zap.String("to", p.To()), 895 ) 896 } 897 898 func (p *proxyServer) CorruptRx(f func([]byte) []byte) { 899 p.corruptRxMu.Lock() 900 p.corruptRx = f 901 p.corruptRxMu.Unlock() 902 p.lg.Info( 903 "corrupting receive", 904 zap.String("from", p.To()), 905 zap.String("to", p.From()), 906 ) 907 } 908 909 func (p *proxyServer) UncorruptRx() { 910 p.corruptRxMu.Lock() 911 p.corruptRx = nil 912 p.corruptRxMu.Unlock() 913 914 p.lg.Info( 915 "stopped corrupting receive", 916 zap.String("from", p.To()), 917 zap.String("to", p.From()), 918 ) 919 } 920 921 func (p *proxyServer) ResetListener() error { 922 p.listenerMu.Lock() 923 defer p.listenerMu.Unlock() 924 925 if err := p.listener.Close(); err != nil { 926 // already closed 927 if !strings.HasSuffix(err.Error(), "use of closed network connection") { 928 return err 929 } 930 } 931 932 var ln net.Listener 933 var err error 934 if !p.tlsInfo.Empty() { 935 ln, err = transport.NewListener(p.from.Host, p.from.Scheme, &p.tlsInfo) 936 } else { 937 ln, err = net.Listen(p.from.Scheme, p.from.Host) 938 } 939 if err != nil { 940 return err 941 } 942 p.listener = ln 943 944 p.lg.Info( 945 "reset listener on", 946 zap.String("from", p.From()), 947 ) 948 return nil 949 }