1
#pragma once
2

            
3
#include <google/protobuf/map.h>
4

            
5
#include <cstdint>
6
#include <memory>
7
#include <string>
8

            
9
#include "envoy/buffer/buffer.h"
10
#include "envoy/network/connection.h"
11

            
12
#include "source/common/buffer/buffer_impl.h"
13
#include "source/common/common/logger.h"
14

            
15
#include "proxylib/libcilium.h"
16
#include "proxylib/types.h"
17

            
18
namespace Envoy {
19
namespace Cilium {
20

            
21
struct GoString {
22
84
  GoString(const std::string& str) : mem_(str.c_str()), len_(str.length()) {}
23
12
  GoString() : mem_(nullptr), len_(0) {}
24

            
25
  const char* mem_;
26
  GoInt len_;
27
};
28

            
29
template <typename T> struct GoSlice {
30
9644
  GoSlice() : data_(nullptr), len_(0) {}
31
9893
  GoSlice(T* data, GoInt len) : data_(data), len_(len), cap_(len) {} // Initialized as full
32
577
  GoInt len() const { return len_; }
33
  GoInt cap() const { return cap_; }
34
  T& operator[](GoInt x) { return data_[x]; }
35
  const T& operator[](GoInt x) const { return data_[x]; }
36
  operator T*() { return data_; }
37
  operator const T*() const { return data_; }
38
  operator void*() { return data_; }
39
  operator const void*() const { return data_; }
40

            
41
  T* data_;
42
  GoInt len_;
43
  GoInt cap_;
44
};
45

            
46
181
inline std::string toString(const FilterResult res) {
47
181
  switch (res) {
48
181
  case FILTER_OK:
49
181
    return "No error";
50
  case FILTER_PARSER_ERROR:
51
    return "Parser error";
52
  case FILTER_UNKNOWN_CONNECTION:
53
    return "Unknown connection";
54
  case FILTER_UNKNOWN_PARSER:
55
    return "Unknown parser";
56
  case FILTER_INVALID_ADDRESS:
57
    return "Invalid address";
58
  case FILTER_POLICY_DROP:
59
    return "Connection rejected";
60
  case FILTER_INVALID_INSTANCE:
61
    return "Invalid proxylib instance";
62
  case FILTER_UNKNOWN_ERROR:
63
    break;
64
181
  }
65
  return "Unknown error";
66
181
}
67

            
68
// Slice that remembers the base pointer and that can be reset.
69
// Note that these have more header data than GoSlices and therefore may not
70
// used as array elements passed to Go!
71
template <typename T> struct ResetableSlice : GoSlice<T> {
72
  // Templated base class member access is a bit ugly
73
  using GoSlice<T>::data_;
74
  using GoSlice<T>::len_;
75
  using GoSlice<T>::cap_;
76

            
77
124
  ResetableSlice(T* data, GoInt cap) : GoSlice<T>(data, cap), base_(data) {
78
124
    len_ = 0; // Init as empty
79
124
  }
80

            
81
  // Non-Go helpers to consume data filled in by Go. Must reset() before slice
82
  // used by Go again.
83
7
  GoInt drain(GoInt len) {
84
7
    if (len > len_) {
85
      len = len_;
86
    }
87
7
    data_ += len;
88
7
    len_ -= len;
89

            
90
7
    return len;
91
7
  }
92
92
  bool atCapacity() {
93
    // Return true if all of the available space was used, not affected by
94
    // draining
95
92
    return (data_ + len_) >= (base_ + cap_);
96
92
  }
97
191
  void reset() {
98
191
    data_ = base_;
99
191
    len_ = 0;
100
191
  }
101

            
102
  // private part not visible to Go
103
  T* base_;
104
};
105

            
106
struct GoStringPair {
107
  GoString key;
108
  GoString value;
109
};
110

            
111
using GoKeyValueSlice = GoSlice<GoStringPair>;
112
using GoOpenModuleCB = uint64_t (*)(GoKeyValueSlice, bool);
113
using GoCloseModuleCB = void (*)(uint64_t);
114

            
115
using GoBufferSlice = ResetableSlice<uint8_t>;
116
using GoOnNewConnectionCB = FilterResult (*)(uint64_t, GoString, uint64_t, bool, uint32_t, uint32_t,
117
                                             GoString, GoString, GoString, GoBufferSlice*,
118
                                             GoBufferSlice*);
119

            
120
using GoDataSlices = GoSlice<GoSlice<uint8_t>>; // Scatter-gather buffer list as '[][]byte'
121
using GoFilterOpSlice = ResetableSlice<FilterOp>;
122
using GoOnDataCB = FilterResult (*)(uint64_t, bool, bool, GoDataSlices*, GoFilterOpSlice*);
123
using GoCloseCB = void (*)(uint64_t);
124

            
125
class GoFilter : public Logger::Loggable<Logger::Id::filter> {
126
public:
127
  GoFilter(const std::string& go_module, const Protobuf::Map<::std::string, ::std::string>&);
128
  ~GoFilter();
129

            
130
  class Instance : public Logger::Loggable<Logger::Id::filter> {
131
  public:
132
18
    Instance(const GoFilter& parent, Network::Connection& conn) : parent_(parent), conn_(conn) {}
133
18
    ~Instance() {
134
18
      if (connection_id_) {
135
        // Tell Go parser to scrap the state kept for the connection
136
18
        (*parent_.go_close_)(connection_id_);
137
18
      }
138
18
    }
139

            
140
    void close();
141

            
142
    FilterResult onIo(bool reply, Buffer::Instance& data, bool end_stream);
143

            
144
38
    bool wantReplyInject() const { return reply_.wantToInject(); }
145
38
    void setOrigEndStream(bool end_stream) { orig_.closed_ = end_stream; }
146
51
    void setReplyEndStream(bool end_stream) { reply_.closed_ = end_stream; }
147

            
148
    struct Direction {
149
36
      Direction() : inject_slice_(inject_buf_, sizeof(inject_buf_)) {}
150

            
151
38
      bool wantToInject() const { return !closed_ && inject_slice_.len() > 0; }
152
      void close() { closed_ = true; }
153

            
154
      Buffer::OwnedImpl buffer_; // Buffered data in this direction
155
      int64_t need_bytes_{0};    // Number of additional data bytes needed before can parse again
156
      int64_t pass_bytes_{0};    // Number of bytes to pass without calling the parser again
157
      int64_t drop_bytes_{0};
158
      bool closed_{false};
159
      GoBufferSlice inject_slice_;
160
      uint8_t inject_buf_[1024];
161
    };
162

            
163
    const GoFilter& parent_;
164
    Network::Connection& conn_;
165
    Direction orig_;
166
    Direction reply_;
167
    uint64_t connection_id_ = 0;
168
  };
169
  using InstancePtr = std::unique_ptr<Instance>;
170

            
171
  InstancePtr newInstance(Network::Connection& conn, const std::string& go_proto, bool ingress,
172
                          uint32_t src_id, uint32_t dst_id, const std::string& src_addr,
173
                          const std::string& dst_addr, const std::string& policy_name) const;
174

            
175
private:
176
  void* go_module_handle_{nullptr};
177
  GoCloseModuleCB go_close_module_;
178
  GoOnNewConnectionCB go_on_new_connection_;
179
  GoOnDataCB go_on_data_;
180
  GoCloseCB go_close_;
181
  uint64_t go_module_id_{0};
182
};
183

            
184
using GoFilterSharedPtr = std::shared_ptr<const GoFilter>;
185

            
186
} // namespace Cilium
187
} // namespace Envoy