Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/extensions/filters/common/lua/wrappers.cc
Line
Count
Source (jump to first uncovered line)
1
#include "source/extensions/filters/common/lua/wrappers.h"
2
3
#include <lua.h>
4
5
#include <cstdint>
6
7
#include "source/common/common/assert.h"
8
#include "source/common/common/hex.h"
9
10
#include "absl/time/time.h"
11
12
namespace Envoy {
13
namespace Extensions {
14
namespace Filters {
15
namespace Common {
16
namespace Lua {
17
18
namespace {
19
20
// Builds a Lua table from a list of strings.
21
template <typename StringList>
22
0
void createLuaTableFromStringList(lua_State* state, const StringList& list) {
23
0
  lua_createtable(state, list.size(), 0);
24
0
  for (size_t i = 0; i < list.size(); i++) {
25
0
    lua_pushlstring(state, list[i].data(), list[i].size());
26
    // After the list[i].data() is pushed to the stack, we need to set the "current element" with
27
    // that value. The lua_rawseti(state, t, i) helps us to set the value of table t with key i.
28
    // Given the index of the current element/table in the stack is below the pushed value i.e. -2
29
    // and the key (refers to where the element is in the table) is i + 1 (note that in Lua index
30
    // starts from 1), hence we have:
31
0
    lua_rawseti(state, -2, i + 1);
32
0
  }
33
0
}
34
35
// By default, LUA_INTEGER is https://en.cppreference.com/w/cpp/types/ptrdiff_t
36
// (https://github.com/LuaJIT/LuaJIT/blob/8271c643c21d1b2f344e339f559f2de6f3663191/src/luaconf.h#L104),
37
// which is large enough to hold timestamp-since-epoch in seconds. Note: In Lua, we usually use
38
// os.time(os.date("!*t")) to get current timestamp-since-epoch in seconds.
39
0
int64_t timestampInSeconds(const absl::optional<SystemTime>& system_time) {
40
0
  return system_time.has_value() ? std::chrono::duration_cast<std::chrono::seconds>(
41
0
                                       system_time.value().time_since_epoch())
42
0
                                       .count()
43
0
                                 : 0;
44
0
}
45
} // namespace
46
47
0
int BufferWrapper::luaLength(lua_State* state) {
48
0
  lua_pushnumber(state, data_.length());
49
0
  return 1;
50
0
}
51
52
0
int BufferWrapper::luaGetBytes(lua_State* state) {
53
0
  const int index = luaL_checkint(state, 2);
54
0
  const int length = luaL_checkint(state, 3);
55
0
  if (index < 0 || length < 0 ||
56
0
      static_cast<uint64_t>(index) + static_cast<uint64_t>(length) > data_.length()) {
57
0
    luaL_error(state, "index/length must be >= 0 and (index + length) must be <= buffer size");
58
0
  }
59
60
  // TODO(mattklein123): Reduce copies here by using Lua direct buffer builds.
61
0
  std::unique_ptr<char[]> data(new char[length]);
62
0
  data_.copyOut(index, length, data.get());
63
0
  lua_pushlstring(state, data.get(), length);
64
0
  return 1;
65
0
}
66
67
0
int BufferWrapper::luaSetBytes(lua_State* state) {
68
0
  data_.drain(data_.length());
69
0
  absl::string_view bytes = getStringViewFromLuaString(state, 2);
70
0
  data_.add(bytes);
71
0
  headers_.setContentLength(data_.length());
72
0
  lua_pushnumber(state, data_.length());
73
0
  return 1;
74
0
}
75
76
0
void MetadataMapHelper::setValue(lua_State* state, const ProtobufWkt::Value& value) {
77
0
  ProtobufWkt::Value::KindCase kind = value.kind_case();
78
79
0
  switch (kind) {
80
0
  case ProtobufWkt::Value::kNullValue:
81
0
    return lua_pushnil(state);
82
0
  case ProtobufWkt::Value::kNumberValue:
83
0
    return lua_pushnumber(state, value.number_value());
84
0
  case ProtobufWkt::Value::kBoolValue:
85
0
    return lua_pushboolean(state, value.bool_value());
86
0
  case ProtobufWkt::Value::kStructValue:
87
0
    return createTable(state, value.struct_value().fields());
88
0
  case ProtobufWkt::Value::kStringValue: {
89
0
    const auto& string_value = value.string_value();
90
0
    return lua_pushlstring(state, string_value.data(), string_value.size());
91
0
  }
92
0
  case ProtobufWkt::Value::kListValue: {
93
0
    const auto& list = value.list_value();
94
0
    const int values_size = list.values_size();
95
96
0
    lua_createtable(state, values_size, 0);
97
0
    for (int i = 0; i < values_size; i++) {
98
      // Here we want to build an array (or a list). Array in lua is just a name for table used in a
99
      // specific way. Basically we want to have: 'elements' table. Where elements[i] is an entry
100
      // in that table, where key = i and value = list.values[i].
101
      //
102
      // Firstly, we need to push the value to the stack.
103
0
      setValue(state, list.values(i));
104
105
      // Secondly, after the list.value(i) is pushed to the stack, we need to set the 'current
106
      // element' with that value. The lua_rawseti(state, t, i) helps us to set the value of table t
107
      // with key i. Given the index of the current element/table in the stack is below the pushed
108
      // value i.e. -2 and the key (refers to where the element is in the table) is i + 1 (note that
109
      // in lua index starts from 1), hence we have:
110
0
      lua_rawseti(state, -2, i + 1);
111
0
    }
112
0
    return;
113
0
  }
114
0
  case ProtobufWkt::Value::KIND_NOT_SET:
115
0
    PANIC("not implemented");
116
0
  }
117
0
}
118
119
void MetadataMapHelper::createTable(lua_State* state,
120
0
                                    const Protobuf::Map<std::string, ProtobufWkt::Value>& fields) {
121
0
  lua_createtable(state, 0, fields.size());
122
0
  for (const auto& field : fields) {
123
0
    int top = lua_gettop(state);
124
0
    lua_pushlstring(state, field.first.data(), field.first.size());
125
0
    setValue(state, field.second);
126
0
    lua_settable(state, top);
127
0
  }
128
0
}
129
130
/**
131
 * Converts the value on top of the Lua stack into a ProtobufWkt::Value.
132
 * Any Lua types that cannot be directly mapped to Value types will
133
 * yield an error.
134
 */
135
0
ProtobufWkt::Value MetadataMapHelper::loadValue(lua_State* state) {
136
0
  ProtobufWkt::Value value;
137
0
  int type = lua_type(state, -1);
138
139
0
  switch (type) {
140
0
  case LUA_TNIL:
141
0
    value.set_null_value(ProtobufWkt::NullValue());
142
0
    break;
143
0
  case LUA_TNUMBER:
144
0
    value.set_number_value(static_cast<double>(lua_tonumber(state, -1)));
145
0
    break;
146
0
  case LUA_TBOOLEAN:
147
0
    value.set_bool_value(lua_toboolean(state, -1) != 0);
148
0
    break;
149
0
  case LUA_TTABLE: {
150
0
    int length = MetadataMapHelper::tableLength(state);
151
0
    if (length > 0) {
152
0
      *value.mutable_list_value() = MetadataMapHelper::loadList(state, length);
153
0
    } else {
154
0
      *value.mutable_struct_value() = MetadataMapHelper::loadStruct(state);
155
0
    }
156
0
    break;
157
0
  }
158
0
  case LUA_TSTRING:
159
0
    value.set_string_value(lua_tostring(state, -1));
160
0
    break;
161
0
  default:
162
0
    luaL_error(state, "unexpected type '%s' in dynamicMetadata", lua_typename(state, type));
163
0
  }
164
165
0
  return value;
166
0
}
167
168
/**
169
 * Returns the length of a Lua table if it's actually shaped like a List,
170
 * i.e. if all the keys are consecutive number values. Otherwise, returns -1.
171
 */
172
0
int MetadataMapHelper::tableLength(lua_State* state) {
173
0
  double max = 0;
174
175
0
  lua_pushnil(state);
176
0
  while (lua_next(state, -2) != 0) {
177
0
    if (lua_type(state, -2) == LUA_TNUMBER) {
178
0
      double k = lua_tonumber(state, -2);
179
0
      if (floor(k) == k && k >= 1) {
180
0
        if (k > max) {
181
0
          max = k;
182
0
        }
183
0
        lua_pop(state, 1);
184
0
        continue;
185
0
      }
186
0
    }
187
0
    lua_pop(state, 2);
188
0
    return -1;
189
0
  }
190
0
  return static_cast<int>(max);
191
0
}
192
193
0
ProtobufWkt::ListValue MetadataMapHelper::loadList(lua_State* state, int length) {
194
0
  ProtobufWkt::ListValue list;
195
196
0
  for (int i = 1; i <= length; i++) {
197
0
    lua_rawgeti(state, -1, i);
198
0
    *list.add_values() = MetadataMapHelper::loadValue(state);
199
0
    lua_pop(state, 1);
200
0
  }
201
202
0
  return list;
203
0
}
204
205
0
ProtobufWkt::Struct MetadataMapHelper::loadStruct(lua_State* state) {
206
0
  ProtobufWkt::Struct struct_obj;
207
208
0
  lua_pushnil(state);
209
0
  while (lua_next(state, -2) != 0) {
210
0
    int key_type = lua_type(state, -2);
211
0
    if (key_type != LUA_TSTRING) {
212
0
      luaL_error(state, "unexpected type %s in table key (only string keys are supported)",
213
0
                 lua_typename(state, key_type));
214
0
    }
215
0
    const char* key = lua_tostring(state, -2);
216
0
    (*struct_obj.mutable_fields())[key] = MetadataMapHelper::loadValue(state);
217
0
    lua_pop(state, 1);
218
0
  }
219
220
0
  return struct_obj;
221
0
}
222
223
MetadataMapIterator::MetadataMapIterator(MetadataMapWrapper& parent)
224
0
    : parent_{parent}, current_{parent.metadata_.fields().begin()} {}
225
226
0
int MetadataMapIterator::luaPairsIterator(lua_State* state) {
227
0
  if (current_ == parent_.metadata_.fields().end()) {
228
0
    parent_.iterator_.reset();
229
0
    return 0;
230
0
  }
231
232
0
  lua_pushlstring(state, current_->first.data(), current_->first.size());
233
0
  MetadataMapHelper::setValue(state, current_->second);
234
235
0
  current_++;
236
0
  return 2;
237
0
}
238
239
0
int MetadataMapWrapper::luaGet(lua_State* state) {
240
0
  const char* key = luaL_checkstring(state, 2);
241
0
  const auto filter_it = metadata_.fields().find(key);
242
0
  if (filter_it == metadata_.fields().end()) {
243
0
    return 0;
244
0
  }
245
246
0
  MetadataMapHelper::setValue(state, filter_it->second);
247
0
  return 1;
248
0
}
249
250
0
int MetadataMapWrapper::luaPairs(lua_State* state) {
251
0
  if (iterator_.get() != nullptr) {
252
0
    luaL_error(state, "cannot create a second iterator before completing the first");
253
0
  }
254
255
0
  iterator_.reset(MetadataMapIterator::create(state, *this), true);
256
0
  lua_pushcclosure(state, MetadataMapIterator::static_luaPairsIterator, 1);
257
0
  return 1;
258
0
}
259
260
0
int SslConnectionWrapper::luaPeerCertificatePresented(lua_State* state) {
261
0
  lua_pushboolean(state, connection_info_.peerCertificatePresented());
262
0
  return 1;
263
0
}
264
265
0
int SslConnectionWrapper::luaPeerCertificateValidated(lua_State* state) {
266
0
  lua_pushboolean(state, connection_info_.peerCertificateValidated());
267
0
  return 1;
268
0
}
269
270
0
int SslConnectionWrapper::luaUriSanLocalCertificate(lua_State* state) {
271
0
  createLuaTableFromStringList(state, connection_info_.uriSanLocalCertificate());
272
0
  return 1;
273
0
}
274
275
0
int SslConnectionWrapper::luaSha256PeerCertificateDigest(lua_State* state) {
276
0
  const std::string& cert_digest = connection_info_.sha256PeerCertificateDigest();
277
0
  lua_pushlstring(state, cert_digest.data(), cert_digest.size());
278
0
  return 1;
279
0
}
280
281
0
int SslConnectionWrapper::luaSerialNumberPeerCertificate(lua_State* state) {
282
0
  const std::string& peer_cert = connection_info_.serialNumberPeerCertificate();
283
0
  lua_pushlstring(state, peer_cert.data(), peer_cert.size());
284
0
  return 1;
285
0
}
286
287
0
int SslConnectionWrapper::luaIssuerPeerCertificate(lua_State* state) {
288
0
  const std::string& peer_cert_serial = connection_info_.issuerPeerCertificate();
289
0
  lua_pushlstring(state, peer_cert_serial.data(), peer_cert_serial.size());
290
0
  return 1;
291
0
}
292
293
0
int SslConnectionWrapper::luaSubjectPeerCertificate(lua_State* state) {
294
0
  const std::string& peer_cert_subject = connection_info_.subjectPeerCertificate();
295
0
  lua_pushlstring(state, peer_cert_subject.data(), peer_cert_subject.size());
296
0
  return 1;
297
0
}
298
299
0
int SslConnectionWrapper::luaUriSanPeerCertificate(lua_State* state) {
300
0
  createLuaTableFromStringList(state, connection_info_.uriSanPeerCertificate());
301
0
  return 1;
302
0
}
303
304
0
int SslConnectionWrapper::luaSubjectLocalCertificate(lua_State* state) {
305
0
  const std::string& subject_local_cert = connection_info_.subjectLocalCertificate();
306
0
  lua_pushlstring(state, subject_local_cert.data(), subject_local_cert.size());
307
0
  return 1;
308
0
}
309
310
0
int SslConnectionWrapper::luaDnsSansPeerCertificate(lua_State* state) {
311
0
  createLuaTableFromStringList(state, connection_info_.dnsSansPeerCertificate());
312
0
  return 1;
313
0
}
314
315
0
int SslConnectionWrapper::luaDnsSansLocalCertificate(lua_State* state) {
316
0
  createLuaTableFromStringList(state, connection_info_.dnsSansLocalCertificate());
317
0
  return 1;
318
0
}
319
320
0
int SslConnectionWrapper::luaValidFromPeerCertificate(lua_State* state) {
321
0
  lua_pushinteger(state, timestampInSeconds(connection_info_.validFromPeerCertificate()));
322
0
  return 1;
323
0
}
324
325
0
int SslConnectionWrapper::luaExpirationPeerCertificate(lua_State* state) {
326
0
  lua_pushinteger(state, timestampInSeconds(connection_info_.expirationPeerCertificate()));
327
0
  return 1;
328
0
}
329
330
0
int SslConnectionWrapper::luaSessionId(lua_State* state) {
331
0
  const std::string& session_id = connection_info_.sessionId();
332
0
  lua_pushlstring(state, session_id.data(), session_id.size());
333
0
  return 1;
334
0
}
335
336
0
int SslConnectionWrapper::luaCiphersuiteId(lua_State* state) {
337
0
  const std::string& cipher_suite_id =
338
0
      absl::StrCat("0x", Hex::uint16ToHex(connection_info_.ciphersuiteId()));
339
0
  lua_pushlstring(state, cipher_suite_id.data(), cipher_suite_id.size());
340
0
  return 1;
341
0
}
342
343
0
int SslConnectionWrapper::luaCiphersuiteString(lua_State* state) {
344
0
  const std::string& cipher_suite = connection_info_.ciphersuiteString();
345
0
  lua_pushlstring(state, cipher_suite.data(), cipher_suite.size());
346
0
  return 1;
347
0
}
348
349
0
int SslConnectionWrapper::luaUrlEncodedPemEncodedPeerCertificate(lua_State* state) {
350
0
  const std::string& peer_cert_pem = connection_info_.urlEncodedPemEncodedPeerCertificate();
351
0
  lua_pushlstring(state, peer_cert_pem.data(), peer_cert_pem.size());
352
0
  return 1;
353
0
}
354
355
0
int SslConnectionWrapper::luaUrlEncodedPemEncodedPeerCertificateChain(lua_State* state) {
356
0
  const std::string& peer_cert_chain_pem =
357
0
      connection_info_.urlEncodedPemEncodedPeerCertificateChain();
358
0
  lua_pushlstring(state, peer_cert_chain_pem.data(), peer_cert_chain_pem.size());
359
0
  return 1;
360
0
}
361
362
0
int SslConnectionWrapper::luaTlsVersion(lua_State* state) {
363
0
  const std::string& tls_version = connection_info_.tlsVersion();
364
0
  lua_pushlstring(state, tls_version.data(), tls_version.size());
365
0
  return 1;
366
0
}
367
368
0
int ConnectionWrapper::luaSsl(lua_State* state) {
369
0
  const auto& ssl = connection_->ssl();
370
0
  if (ssl != nullptr) {
371
0
    if (ssl_connection_wrapper_.get() != nullptr) {
372
0
      ssl_connection_wrapper_.pushStack();
373
0
    } else {
374
0
      ssl_connection_wrapper_.reset(SslConnectionWrapper::create(state, *ssl), true);
375
0
    }
376
0
  } else {
377
0
    lua_pushnil(state);
378
0
  }
379
0
  return 1;
380
0
}
381
382
} // namespace Lua
383
} // namespace Common
384
} // namespace Filters
385
} // namespace Extensions
386
} // namespace Envoy